반응형
Spring Data JPA 게시글은 대부분 인프런의 김영한님의 강의인 '실전! 스프링 데이터 JPA' 기반으로 내용을 정리했습니다.
Auditing
- 엔티티를 생성, 변경할 때 변경한 사람과 시간을 추적하고 싶을 때 사용한다.
- 기본적으로 테이블을 생성할 때 등록일과 수정일 컬럼을 넣는다. 왜냐하면 운영할 때 기본적으로 추적이 쉽기 때문이다.
- 추가적으로 등록자, 수정자도 추가로 넣을 수 있다.
- 위의 등록일, 수정일은 거의 모든 테이블에 공통적으로 들어가 있는 컬럼으로 생각하면 된다.(등록자, 수정자는 필요 없는 테이블에선 추가하지 않는다.)
순수 JPA 사용
- JapBaseEntity.class
@Getter
@MappedSuperclass
public class JpaBaseEntity {
@Column(updatable = false)
private LocalDateTime createDate;
private LocalDateTime updateDate;
@PrePersist
public void prePersist() {
LocalDateTime now = LocalDateTime.now();
createDate = now;
updateDate = now; //수정일이 null이어도 되지만 값을 넣어두면 나중에 쿼리 날릴 때 편하다.
}
@PreUpdate
public void perUpdate() {
updateDate = LocalDateTime.now();
}
}
- @MappedSuperclass : 매핑 정보만 제공하도록 설정하는 애노테이션. 잘 모르면 아래 글을 참조하면 된다.
- @Column(updatable = false) : 해당 필드를 실수로 수정하더라도 update 쿼리가 반영되지 않도록 하는 애노테이션
- @PrePersist : em.persist()의 기능을 수행하기 전에 이벤트 성으로 동작할 수 있도록하는 애노테이션
- @PreUpdate : update 전에 이벤트 성으로 동작할 수 있도록 하는 애노테이션
- Test 코드
@Test
public void JpaEventBaseEntity() throws Exception {
Member member = new Member("member1");
memberRepository.save(member); // PrePersist 발생
Thread.sleep(100);
member.setUsername("member2");
em.flush(); // PreUpdate 발생
em.clear();
Member findMember = memberRepository.findById(member.getId()).get();
System.out.println("findMember.createDate() = " + findMember.getCreateDate());
System.out.println("findMember.updateDate() = " + findMember.getUpdateDate());
}
select
member0_.member_id as member_i1_0_0_,
member0_.create_date as create_d2_0_0_,
member0_.update_date as update_d3_0_0_,
member0_.age as age4_0_0_,
member0_.team_id as team_id6_0_0_,
member0_.username as username5_0_0_
from
member member0_
where
member0_.member_id=?
findMember.createDate() = 2022-07-31T21:44:17.081741
findMember.updateDate() = 2022-07-31T21:44:17.215482
스프링 데이터 JPA 사용
설정(필수)
- @EnableJpaAuditing : 스프링 부트 설정 클래스에 적용
- @EntityListeners(AuditingEntityListener.class) : 엔티티에 적용
- DataJpaApplication.class
@EnableJpaAuditing // 추가
@SpringBootApplication
public class DataJpaApplication {
- BaseEntity.class
@EntityListeners(AuditingEntityListener.class)
@MappedSuperclass
@Getter
public class BaseEntity {
@CreatedDate
@Column(updatable = false)
private LocalDateTime createDate;
@LastModifiedDate
private LocalDateTime lastModifiedDate;
}
- Member.class
public class Member extends BaseEntity
등록자, 수정자 추가
- BaseEntity.class
@CreatedBy
@Column(updatable = false)
private String createBy;
@LastModifiedBy
private String lastModifiedBy;
- DataJpaApplication.class
@Bean
public AuditorAware<String> auditorProvider() {
return () -> Optional.of(UUID.randomUUID().toString());
}
이렇게 빈을 만들어두면 등록, 수정이 될 때마다 auditorProvider()를 호출해서 UUID 값을 가져온다. 테스트 코드에서 createBy와 lastModifiedBy를 출력하는 코드를 작성하여 실행시키면 다음과 같이 잘 출력 되는 걸 볼 수 있다.
findMember.createDate() = 2022-07-31T22:03:41.844716
findMember.lastModifiedDate() = 2022-07-31T22:03:41.973969
findMember.createBy() = c6fa278e-3da8-4611-9a15-36b94fe546c8
findMember.lastModifiedBy() = a4a88166-0c2f-49d5-ba20-8f1e9d049ed8
실무에서는 랜덤 값이 아닌 세션 아이디 값 등을 가져와서 세팅하면 된다.
! 위에서도 말했지만 등록일, 수정일은 웬만해서 모든 테이블에 들어가는 컬럼이고, 등록자와 수정자는 테이블의 성격에 따라서 들어갈 수도, 안 들어갈 수도 있다. 그런데 위의 예제와 같이 한 클래스에 등록일, 수정일, 등록자, 수정자를 모두 밀어 넣어버리면 굳이 안 들어가도 될 등록자, 수정자를 모든 테이블이 갖게 된다. 그러니 BaseTimeEntity를 따로 만들어 등록일, 수정일 필드를 세팅하고 BaseEntity에서 BaseTimeEntity를 상속받도록 세팅한다.
반응형