본문 바로가기
ORM/JPA

[JPA] JPA Auditing 정리 및 구현

by 젊은오리 2023. 4. 10.
728x90

서론

JPA를 사용하여 도메인을 관계형 데이터베이스 테이블에 매핑할 때 공통적으로 도메인들이 가지고 있는 필드나 컬럼들이 존재한다. ex) 생성 일자, 수정 일자, 생성자, 수정자...

도메인마다 공통으로 존재한다는 의미는 결국 코드가 중복된다는 것을 의미한다. 그래서 JPA에서는 Audit이라는 기능을 제공한다 Audit은 Spring Data JPA에서 시간에 대해서 자동으로 값을 넣어주는 기능이다. 도메인을 영속성 컨텍스트에 저장하거나 조회를 수행한 후에 update를 하는 경우 매번 시간 데이터를 입력하여 주어야 하는데, Audit을 이용하면 자동으로 시간을 매핑하여 데이터베이스의 테이블에 넣어주게 된다. JPA Audit은 데이터의 변경 기록을 추적하고 데이터 변화에 대한 이력을 기록하는 것을 목적으로 한다.

구현 예시

가장 먼저 Auditing이 필요한 Entity에서 상속받을 BaseEntity를 생성해야 한다.

  • 대부분의 테이블에 createdTime과 modifiedTime은 필요하지만 createdBy과 modifiedBy는 특정 테이블에서만 필요한 경우가 많다. 따라서 createdBy과 modifiedBy는 선택적으로 사용할 수 있도록 MappedSuperclass를 BaseEntity와 BaseTimeEntity로 나눈다.
  • BaseTimeEntity를 최상위 부모로 사용하면 Member와 같은 생성자, 수정자가 필요없는 Entity는 BaseTimeEntity만 상속 받아 해결할 수 있다.

 

[BaseTimeEntity]

@EntityListeners(value = {AuditingEntityListener.class})
@MappedSuperclass
@Getter
public abstract class BaseTimeEntity {

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

    @LastModifiedDate
    private LocalDateTime modifiedTime;
}

 

[BaseEntity]

@EntityListeners(value = {AuditingEntityListener.class})
@MappedSuperclass
@Getter
public abstract class BaseEntity extends BaseTimeEntity{

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

    @LastModifiedBy
    private String modifiedBy;
}
  • @MappedSuperclass : Entity에서 공통 매핑 정보가 필요할 때 상속받아 사용할 수 있게 한다.(중복 제거)
  • @CreatedData : Entity가 생성될 때 자동으로 생성 시간이 저장된다.
  • @LastModifiedData : Entity가 수정될 때 자동으로 수정시간이 저장된다.
  • @CreatedBy : Entity가 생성될 때 자동으로 생성자가 저장된다.
  • @LastModifiedBy : Entity가 수정될 때 자동으로 수정자가 저장된다.

 

Entity가 상속 받을 BaseEntity와 BaseTimeEntity를 만들었다면, 이제 @CreatedBy와 @ModifiedBy를 사용하기 위해 AuditorAware를 스프링 빈으로 등록해야 한다.(날짜와 다르게 생성자, 수정자는 JPA에서 알 수 없기에 개발자가 직접 알려줘야 하기 때문)

따라서 다음과 같이 JpaConfig 설정 클래스를 만든 다음 AuditorAware를 빈으로 등록한다. 

[JpaConfig]

@Configuration
@EnableJpaAuditing
public class JpaConfig {
    @Bean
    public AuditorAware<String> auditorAware(){ //AuditorAware을 빈으로 등록
        return new AuditorAwareImpl();
    }
}
  • @Configuration : 설정 클래스이므로 빈에 등록한다.
  • @EnableJpaAuditing : JPA Auditing기능을 활성화한다.

 

이제 아래에서 AuditorAware의 구현체인 AuditorAwareImpl을 만들어보자.

[AuditorAwareImpl]

public class AuditorAwareImpl implements AuditorAware<String> {

    @Autowired
    private HttpServletRequest httpServletRequest;

    @Override
    public Optional<String> getCurrentAuditor() {
        String modifiedBy = httpServletRequest.getRequestURI();
        if(!StringUtils.hasText(modifiedBy)) {
            modifiedBy = "unknown";
        }
        return Optional.of(modifiedBy);
    }
}

AuditorAwareImpl은 AuditorAware 인터페이스의 구현체이며, Optional<>을 반환하는 getCurrentAuditor 메서드를 필수로 override해야 한다. 여기서는 HttpServletRequest의 요청URI를 수정자로 정하고, Optional형태로 반환하게 했다.

이제 Entity에서 아래와 같이 @EntityListener를 추가하면 자동으로 생성시간, 수정시간이 추가된다.

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@EntityListeners(value = {AuditingEntityListener.class}) //추가
public class Member extends BaseTimeEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long memberId;

    private String name;
}

 

 

Reference : https://web-km.tistory.com/42

728x90

댓글