JPA/스프링 데이터 JPA

Auditing - 엔티티의 생성 변경 기록

chanhee01 2023. 8. 12. 14:57

엔티티를 생성과 변경을 할 때 변경을 한 사람, 시간 기록을 남겨두면 운영 과정에서 훨씬 도움이 될 것이다.

 

 

순수 JPA에서의 Auditing

 

1. JpaBaseEntity라는 날짜 속성을 알려주는 엔티티를 만든다.

@Getter
@MappedSuperclass // 진짜 상속은 아니고 선언된 속성들만 사용한다는 것
public class JpaBaseEntity {

    @Column(updatable = false)
    private LocalDateTime createdDate;
    private LocalDateTime updatedDate;

    @PrePersist
    public void prePersist() {
        LocalDateTime now = LocalDateTime.now();
        createdDate = now;
        updatedDate = now;
    }

    @PreUpdate
    public void preUpdate() {
        updatedDate = LocalDateTime.now();
    }
}

 

 

2. Member 엔티티에서 JpaBaseEntity를 상속 받는다.

public class Member extends JpaBaseEntity {
    ....
}

 

 

3. 테스트에서 실행해보면 만든 날짜와 수정 날짜가 나온다.

@Test
public void JpaEventBaseEntity() throws Exception {
    //given
    Member member = new Member("member1");
    memberRepository.save(member); // @PerPersist 발생

    Thread.sleep(100);
    member.setUsername("member2");

    em.flush(); // @PreUpdate
    em.clear();

    //when
    Member findMember = memberRepository.findById(member.getId()).get();

    //then
    System.out.println("findMember.getCreatedDate = " + findMember.getCreatedDate());
    System.out.println("findMember.getUpdatedDate = " + findMember.getUpdatedDate());
}

 

콘솔 결과 창

findMember.getCreatedDate = 2023-08-12T14:36:13.643212
findMember.getUpdatedDate = 2023-08-12T14:36:13.795051

 

 

장점은 모든 엔티티에 JpaBaseEntity를 상속 시킬 수 있다. Team의 수정시간을 보고 싶을 때에도 팀에 JpaBaseEntity를 상속 시키면 되니까 엔티티별로 따로 만들 필요가 없다.

 

 

 

 

 

스프링 데이터 JPA 사용

 

 

1. Main 클래스에 무조건 @EnableJpaAuditing 어노테이션 넣어줘야 함

@EnableJpaAuditing // 필수!
@SpringBootApplication
public class DataJpaApplication {

	public static void main(String[] args) {
		SpringApplication.run(DataJpaApplication.class, args);
	}

}

 

 

2. BaseEntity 클래스 생성

@EntityListeners(AuditingEntityListener.class)
@MappedSuperclass
@Getter
public class BaseEntity {

    @CreatedDate
    @Column(updatable = false)
    private LocalDateTime createdDate;

    @LastModifiedDate
    private LocalDateTime lastModifiedDate;
}

생성 날짜는 @CreatedDate, 수정 날싸는 @LastModifiedDate로 한다.

@EntityListeners(AuditingEntityListener.class)는 변경이 있을 때만 동작한다는 어노테이션? 그런 의미이다.

 

 

3. Member의 상속 엔티티 교체

public class Member extends BaseEntity {
    ....
}

이후의 작업은 나머지와 동일한데 스프링 데이터 JPA를 사용하니 훨씬 간편해졌다.

 

 

 

 

- 날짜 뿐만 아니라 변경한 사용자도 알려주기

 

 

1. BaseEntity에 엔티티 추가

@EntityListeners(AuditingEntityListener.class)
@MappedSuperclass
@Getter
public class BaseEntity {

    @CreatedDate
    @Column(updatable = false)
    private LocalDateTime createdDate;

    @LastModifiedDate
    private LocalDateTime lastModifiedDate;

    @CreatedBy
    @Column(updatable = false)
    private String createBy;

    @LastModifiedBy
    private String lastModifiedBy;
}

@CreatedBy는 생성한 사람, @LastModifiedBy는 수정한 사람을 칭한다.

 

 

2. 메인 클래스에 스프링 빈 주입

@EnableJpaAuditing
@SpringBootApplication
public class DataJpaApplication {

	public static void main(String[] args) {
		SpringApplication.run(DataJpaApplication.class, args);
	}

	@Bean
	public AuditorAware<String> auditorProvider() {
		return () -> Optional.of(UUID.randomUUID().toString());
		// 원래는 스프링 시큐리티에서 세션을 꺼낸 다음에 그 id를 넣어줘야 한다.
	}
}

auditorProvier()라는 스프링 빈을 주입한다. 원래는 UUID 값이 아니라 스프링 시큐리티나 http에서 세션을 꺼낸 다음 그 사람의 id를 넣어줘야 하는데, 지금은 예제니까 UUID를 사용했다.

 

 

3. 테스트

@Test
public void JpaEventBaseEntity() throws Exception {
    //given
    Member member = new Member("member1");
    memberRepository.save(member); // @PerPersist 발생

    Thread.sleep(100);
    member.setUsername("member2");

    em.flush(); // @PreUpdate
    em.clear();

    //when
    Member findMember = memberRepository.findById(member.getId()).get();

    //then
    System.out.println("findMember.getCreatedDate = " + findMember.getCreatedDate());
    System.out.println("findMember.getUpdatedDate = " + findMember.getLastModifiedDate());
    System.out.println("findMember.getCreatedBy = " + findMember.getCreateBy());
    System.out.println("findMember.getUpdatedBy = " + findMember.getLastModifiedBy());
}

테스트를 해보면 시간 이외에 생성, 변경한 사람의 UUID도 출력해준다.

 

콘솔 결과 창

findMember.getCreatedDate = 2023-08-12T14:49:40.986619
findMember.getUpdatedDate = 2023-08-12T14:49:41.130150
findMember.getCreatedDate = d63da64a-e66c-48da-b173-4a940a7a4672
findMember.getUpdatedDate = 9dd20bcb-dd73-42e2-ae4c-5f5615c961e8