JPA의 Auditing 기능 INSERT, UPDATE시 시간 저장하기

2023-05-31
ꞏ
유영진
ꞏ
show5116

JPA에서는 Audit기능을 제공해줍니다.
Audit은 감시하다 라는 뜻으로, 이 기능을 활용하면 생성일, 수정일, 생성한 사람, 수정한 사람의 정보를 남길 수 있습니다.

@MappedSuperclass

mappedSuperclass size:800*400 @MappedSuperclass 어노테이션은 부모클래스에 선언하여서 상속받는 Entity들은 모두 상속받은 컬럼을 가지게 해줍니다.
이 어노테이션을 사용한 클래스는 엔티티가 아니고, 상속관계 매핑이 아닙니다.
위의 이미지와 같이 BaseEntity란 부모클래스가 id와 name이란 컬럼을 가지고 있다면, Member와 Seller Entity는 이를 상속받아 두개의 컬럼을 가지게 됩니다.

java
1@MappedSuperclass
2@Getter
3public abstract class BaseEntity {
4 @Column(name = "create_user", columnDefinition = "varchar2(50)", nullable = false, updatable = false)
5 private String createUser;
6
7 @Column(name = "change_user", columnDefinition = "varchar2(50)", nullable = false)
8 private String modifyUser;
9
10 @Column(name = "create_time", columnDefinition = "date", nullable = false, updateable = false)
11 private LocalDateTime createDateTime;
12
13 @Column(name = "change_time", columnDefinition = "date", nullable = false)
14 private LocalDateTime modifyDateTime;
15
16}

위에는 createUser, modifyUser, createDateTime, modifyDateTime 4개의 컬럼을 가진 추상클래스를 만들었습니다.

java
1@Entity
2@Table(name = "users")
3public class User extends BaseEntity {
4 ......
5}

이런방식으로 해당 4개의 컬럼이 필요한 Entity에서 BaseEntity를 상속받으면 4개의 컬럼을 가지게 됩니다.
대부분의 Entity는 생성시간과 수정시간을 저장해두면 좋으니 상속받아 구현하면 좋습니다.

Audit 사용하기

@MappedSuperclass을 이용해 추상클래스를 구현하였다면, 이젠 Audit 기능을 사용하여서 INSERT, UPDATE시에 저 컬럼들에 값을 자동으로 넣도록 할 수 있습니다.

Config

Audit을 위한 Configuration 파일을 생성해줍니다.
@EnableJpaAuditing어노테이션은 사용한 어플리케이션에 JPA Audit 기능을 제공해주게 되는 어노테이션입니다.
메인 어플리케이션 클래스에서 사용하여도 상관없지만, Test코드를 이용할 때와 또한 정확하게 기능을 구분하기 위해 따로 사용하는 것이 좋습니다.

java
1@Configuration
2@EnableJpaAuditing
3public class AuditingConfig implements AuditorAware<String> {
4
5 @Override
6 public Optional<String> getCurrentAuditor() {
7 HttpServletRequest currentRequest = WebHelper.getCurrentRequest();
8 String memberId = currentRequest.getHeader("member-id");
9 memberId = memberId.isEmpty() ? "System" : memberId;
10 return Optional.of(memberId);
11 }
12}
java
1public class WebHelper {
2 public static HttpServletRequest getCurrentRequeset() {
3 return ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
4 }
5}

AuditorAware을 implements하면 getCurrentAuditor 메서드를 구현하게 됩니다.
해당 클래스는 추후에 createUser와 modifyUser에 들어가게 될 값을 정해줍니다.
현재 HttpServletRequest를 가져오고, RequestHeader를 통해 member-id를 넣어줍니다.
혹여 member-id가 없는 상황(Spring 스케쥴러를 통한 상황, 혹은 회원 가입 등..)에선 System이란 아이디를 넣어줍니다.

추상클래스 변경

앞에서 만들었던 추상클래스를 변경해주도록 하겠습니다.
@EntityListeners 어노테이션은 JPA Entity에서 이벤트가 발생할 때마다 특정 로직을 실행시킬 수 있게 해주는 어노테이션입니다.
AuditingEntityListener.class의 값을 주면 @PrePersist로 Audit 기능을 수행하게 해줍니다.

java
1@MappedSuperclass
2@EntityListeners(AuditingEntityListener.class)
3@Getter
4public abstract class Auditalbe {
5 @CreatedBy
6 @Column(name = "create_user", columnDefinition = "varchar2(50)", nullable = false, updatable = false)
7 protected String createUser;
8
9 @LastModifiedBy
10 @Column(name = "change_user", columnDefinition = "varchar2(50)", nullable = false)
11 protected String modifyUser;
12
13 @CreatedDate
14 @Column(name = "create_time", columnDefinition = "date", nullable = false, updateable = false)
15 protected LocalDateTime createDateTime;
16
17 @LastModifiedDate
18 @Column(name = "change_time", columnDefinition = "date", nullable = false)
19 protected LocalDateTime modifyDateTime;
20
21}
  • @CreatedDate

Entity가 INSERT될 때 생성 시간을 넣어줍니다.
JPA에서 제공하는 @CreateDate 말고 Hibernate에서 제공하는 @CreationTimestamp이란 어노테이션도 존재합니다.
둘의 차이점은 @CreateDate는 위에서 한 것과 같이 @EnableJpaAuditing과 @EntityListeners를 필요로 합니다.
반면에 @CreationTimestamp는 그러한 설정없이 동작이 가능합니다.
그 이유는 JPA는 JPA 고유 메모리 공간(context)을 이용해 Entity 객체들을 관리하는데 관리되는 객체들이 변경되면 데이터에 반영하는 형식이라 변화를 감지해야 하기 때문입니다.

  • @LastModifiedDate

Entity가 UPDATE될 때 수정 시간을 넣어줍니다.
마찬가지로 Hibernate에서 제공하는 @UpdateTimestamp이란 어노테이션이 존재해서 대신 사용해도 됩니다.

  • @CreatedBy

Entity가 INSERT될 때 getCurrentAuditor메서드를 통해 얻어온 값을 넣어줍니다.

  • @LastModifiedBy

마찬가지로 Entity가 UPDATE될 때 getCurrentAuditor메서드를 통해 얻어온 값을 넣어줍니다.