Spring/Spring Data JPA

Spring Data JPA - 엔티티의 생성, 변경한 사람과 시간을 추적(Auditing)

jddng 2022. 3. 21. 11:34
728x90
반응형

 

 

엔티티의 생성, 변경한 사람과 시간을 추적(Auditing)

 

  • 기본적으로 운영할 때는 등록일, 수정일, 등록자, 수정자를 모든 테이블에 적용하는 것이 좋다. 
  • 누가 등록했고, 누가 수정했는지 추적하기가 쉽다.
  • 유지보수에 용이

 

 

 

순수 JPA 사용의 Auditing

 

  • @MappedSuperclass : 해당 필드들을 사용할 수 있도록 맵핑해주는 어노테이션
  • @PrePersist : 저장할 때 이벤트 실행
  • @PreUpdate : 수정할 때 이벤트 실행

 

1. 모든 Entity에 적용하는 공통 Entity 생성

@MappedSuperclass
@Getter
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. Entity에 상속받아 사용

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());
}

 

Spring Data JPA에서의 Auditing

 

  • 설정 - @EnableJpaAuditing : 스프링 부트 설정 클래스에 적용해야 한다.(ex - xxxxapplication.class)
  •        - @EntityListeners(AuditingEntityListener.class) : 엔티티에 적용해야 한다.
  • 사용 어노테이션
             - @CreatedDate
             - @LastModifiedDate
             - @CreateBy
             - @LastModifiedBy

 

1. 모든 Entity에 적용하는 공통 Entity 생성

@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 createdBy;
    
    @LastModifiedBy
    private String lastModifiedBy;
}

 

2. Entity에 상속받아 사용

public class Member extends BaseEntity {
	...
}

 

3. 등록자, 수정자를 처리해주는 AuditorAware 스프링 빈 등록( xxxxApllication.class)

   실무에서는 세션 정보나, 스프링 시큐리티 로그인 정보에서 ID를 받는다.

@Bean
public AuditorAware<String> auditorProvider() {
    return () -> Optional.of(UUID.randomUUID().toString());
}

 

 

 

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

 

public class BaseTimeEntity {
    @CreatedDate
    @Column(updatable = false)
    private LocalDateTime createdDate;
    
    @LastModifiedDate
    private LocalDateTime lastModifiedDate;
}
public class BaseEntity extends BaseTimeEntity {
    @CreatedBy
    @Column(updatable = false)
    private String createdBy;
    
    @LastModifiedBy
    private String lastModifiedBy;
}

 

 


 

참고
임베디드 타입과 @MappedSuperclass의 차이는
선택의 차이일뿐

 

상속을 사용하는 것(@MappedSuperclass) 위임을 사용하는 것(임베디드)의 차이

JPQL 쿼리를 사용할 때 상속과 위임의 차이는 다음과 같다.

 

임베디드 : select m from Member m where m.traceDate.createdDate > ?

 

상속 : select m from Member m where m.createdDate > ?

 

728x90
반응형