SpringDataJPA - Auditing

박민수·2023년 11월 14일
0

JPA

목록 보기
22/24
post-thumbnail

Auditing

SpringDataJPA에서는 Auditing이라는 기능을 제공한다. 해당 기능을 사용하여 엔티티가 생성되고, 변경되는 시점을 감지하여 등록일, 수정일, 등록자, 수정자 등을 확인할 수 있다. 기본적으로 테이블을 만들 때 등록일과 수정일은 반드시 남겨놓는 것이 좋다.
등록일과 수정일을 남겨놓지 않으면 문제가 생겼을 때 추적이 불가능하여 로그를 일일이 다 뒤져봐야 하기 때문에 매우 번거로워진다.

이번 포스팅에서는 Auditing 기능을 사용해서 엔티티의 등록일, 수정일, 등록자, 수정자 등을 자동으로 기록하는 방법에 대해서 알아 보고자 한다.

Auditing(with. JPA)

먼저 순수 JPA를 이용한 Auditing 기능을 알아보자.
JPA에서는 다음과 같은 이벤트 어노테이션을 제공한다.

  • @PrePersist, @PreUpdate : Persist 혹은 Update 전에 이벤트가 발생한다.
  • @PostPersist, @PostUpdate : Persist 혹은 Update 후에 이벤트가 발생한다.
package study.datajpa.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();
    }
}

등록일, 수정일을 적용 할 대상 엔티티에 우리가 구현한 JpaBaseEntity 클래스를 상속한다.

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

Auditing(with. SpringDataJPA)

SpringDataJPA에서 제공하는 Auditing 기능을 사용하려면 스프링 부트 설정 클래스에 @EnableJpaAuditing 어노테이션을 적용해야한다.

@EnableJpaAuditing
@SpringBootApplication
public class DataJpaApplication {
	public static void main(String[] args) {SpringApplication.run(DataJpaApplication.class, args);
}

등록일, 수정일

package study.datajpa.entity;

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

등록자, 수정자

등록자, 수정자에 자동으로 값이 할당되게 하려면 별도로 AuditorAware 스프링 빈을 등록해줘야 한다. 해당 빈을 등록해 줘야 등록자, 수정자에 값이 들어간다. (실무에서는 세션 정보나, 스프링 시큐리티 로그인 정보에서 ID를 받음)

@Bean
public AuditorAware<String> auditorProvider() {
    return () -> Optional.of(UUID.randomUUID().toString());
}
@EntityListeners(AuditingEntityListener.class)
@MappedSuperclass
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;
}

전체 적용

@EntityListeners(AuditingEntityListener.class) 를 생략하고 스프링 데이터 JPA 가 제공하는 이벤트를 엔티티 전체에 적용하려면 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>

추가 Tip

실무에서 대부분의 엔티티는 등록시간, 수정시간이 필요하지만, 등록자, 수정자는 없을 수도 있다. 그래서 다음과 같이 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;
}

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


참조
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EB%8D%B0%EC%9D%B4%ED%84%B0-JPA-%EC%8B%A4%EC%A0%84/dashboard

profile
안녕하세요 백엔드 개발자입니다.

0개의 댓글