오봉이와 함께하는 개발 블로그

스프링 데이터 JPA - Auditing 본문

BE/JPA

스프링 데이터 JPA - Auditing

오봉봉이 2022. 9. 14. 01:23
728x90

Auditing

  • 엔티티를 생성, 변경할 때 변경한 사람과 시간을 추적하고 싶으면?
    • 등록일
    • 수정일
    • 등록자
    • 수정자

순수 JPA 사용

우선 등록일, 수정일을 적용해보자.

@MappedSuperclass // 상속 관계가 아니라 속성만 내려줘서 데이터를 같이 사용할 수 있게 할 수 있다.
@Getter
public class JpaBaseEntity {

    @Column(updatable = false) // createdDate는 update가 불가능하게 설정.
    private LocalDateTime createdDate;
    private LocalDateTime updatedDate;

    @PrePersist // persist 하기 전에 이벤트를 자동 발생시킴.
    public void prePersist() {
        LocalDateTime now = LocalDateTime.now();
        this.createdDate = now;
        this.updatedDate = now;
    }
    @PreUpdate // update 하기 전에 이벤트를 자동 발생시킴.
    public void preUpdate() {
        this.updatedDate = LocalDateTime.now();
    }
}
public class Member extends JpaBaseEntity {
    // .............
}
@Test
public void JpaEventBaseEntity() throws Exception {
    // given
    Member member = new Member("member1");
    memberRepository.save(member); //@PrePersist
    Thread.sleep(100);
    member.setUsername("member2");
    em.flush(); //@PreUpdate
    em.clear();
    // when
    Member findMember = memberRepository.findById(member.getId()).get();
    // then
    System.out.println("findMember.createdDate = " + findMember.getCreatedDate());
    System.out.println("findMember.updatedDate = " + findMember.getUpdatedDate());
}
findMember.createdDate = 2022-09-14T01:06:06.164855
findMember.updatedDate = 2022-09-14T01:06:06.315108
  • JPA 주요 이벤트 어노테이션
    • @PrePersist, @PostPersist
    • @PreUpdate, @PostUpdate

스프링 데이터 JPA 사용

  • 설정
    • @EnableJpaAuditing 스프링 부트 설정 클래스에 적용해야함
@SpringBootApplication
@EnableJpaAuditing
public class DataJpaApplication {
    public static void main(String[] args) {
        SpringApplication.run(DataJpaApplication.class, args);
    }
}
@MappedSuperclass
@Getter
@EntityListeners(AuditingEntityListener.class)
public class BaseEntity {

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

    @LastModifiedDate
    private LocalDateTime lastModifiedDate; // updatedDate

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

    @LastModifiedBy
    private String lastModifiedBy;
}

테스트 코드는 getUpdatedDate() -> getLastModifiedDate()

  • 사용 어노테이션
    • @CreatedDate
    • @LastModifiedDate
    • @CreatedBy
    • @LastModifiedBy

등록자, 수정자는 처리해주는 AuditorAware를 스프링 빈 등록해야 한다.

@Bean
public AuditorAware<String> auditorProvider() {
    return new AuditorAware<String>() {
        @Override
        public Optional<String> getCurrentAuditor() {
            return Optional.of(UUID.randomUUID().toString());
        }
    };
}
// 위 코드를 람다로 아래처럼 바꿀 수 있다.
@Bean
public AuditorAware<String> auditorProvider() {
    return () -> Optional.of(UUID.randomUUID().toString());
}

여기서는 UUID를 넣었지만 실무에서는 세션 정보나, 스프링 시큐리티 로그인 정보에서 ID를 받는다.

실무에서 대부분의 엔티티는 등록시간, 수정시간이 필요하지만, 등록자, 수정자는 없을 수도 있다.
그래서 다음과 같이 Base 타입을 분리하고, 원하는 타입을 선택해서 상속한다.

@MappedSuperclass
@Getter
@EntityListeners(AuditingEntityListener.class)
public class BaseTimeEntity {
    @CreatedDate
    @Column(updatable = false)
    private LocalDateTime createdDate;

    @LastModifiedDate
    private LocalDateTime lastModifiedDate;
}

@MappedSuperclass
@Getter
@EntityListeners(AuditingEntityListener.class)
public class BaseEntity extends BaseTimeEntity {
    @CreatedBy
    @Column(updatable = false)
    private String createdBy;

    @LastModifiedBy
    private String lastModifiedBy;
}

저장시점에 등록일, 등록자는 물론이고, 수정일, 수정자도 같은 데이터가 저장된다. 데이터가 중복 저장되는 것 같지만, 이렇게 해두면 변경 컬럼만 확인해도 마지막에 업데이트한 유저를 확인 할 수 있으므로 유지보수 관점에서 편리하다. 이렇게 하지 않으면 변경 컬럼이 null 일때 등록 컬럼을 또 찾아야 한다. 참고로 저장시점에 저장데이터만 입력하고 싶으면 @EnableJpaAuditing(modifyOnCreate = false)옵션을 사용하면 된다.

전체 적용

@EntityListeners(AuditingEntityListener.class)를 생략하고 스프링 데이터 JPA가 제공하는 이벤트를 엔티티 전체에 적용하려면 orm.xml에 다음과 같이 등록하면 된다.

META-INF/orm.xml

?xml version=“1.0” encoding="UTF-8”?>
    <entity-mappings xmlns=“http://xmlns.jcp.org/xml/ns/persistence/orm”
                     xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
                     xsi:schemaLocation=“http://xmlns.jcp.org/xml/ns/persistence/orm http://xmlns.jcp.org/xml/ns/persistence/orm_2_2.xsd”
                     version=“2.2">
        <persistence-unit-metadata>
            <persistence-unit-defaults>
                <entity-listeners>
                    <entity-listener
    class="org.springframework.data.jpa.domain.support.AuditingEntityListener”/>
                </entity-listeners>
            </persistence-unit-defaults>
        </persistence-unit-metadata>
    </entity-mappings>
인프런 김영한 지식공유자님 강의 : 실전! 스프링 데이터 JPA
728x90
Comments