JPA : Base Entity 사용한 Audit 기능 사용하기
- Spring/JPA
- 2022. 2. 5.
이 글은 인프런의 김영한님의 강의를 보고 복습하며 작성한 글입니다.
Audit
Audit이란 DB를 관리하기 편하도록 DB에 값을 넣을 때, 항상 특정 데이터가 포함되도록 하는 것이다. 이렇게 관리하게 되면, 추후에 DB에서의 문제점을 Trace하는데 많은 도움이 된다고 한다. 따라서 Audit을 하는 것은 거의 필수적이다.
- 최초 등록 시간
- 마지막 수정 시간
- 최초 등록한 사람
- 마지막 수정한 사람
Audit을 할 때 주로 사용되는 데이터는 위의 4개로 정리를 할 수 있다. 딱 보면 감이 오겠지만, DB에서 문제가 발생했을 때 추적을 하는데 용이하게 쓸 수 있는 값으로 보인다.
Audit, 어떻게 하면 스마트한가?
등록, 수정한 사람은 모르더라도 최초 등록한 시간, 마지막 수정한 시간은 DB의 모든 테이블에서 광범위하게 사용될 것이 분명한 값이다. 이 값을 각 객체에 필드로 하나씩 추가하고, 각 메서드에 하나하나 넣는 방법으로 구현을 할 수도 있을 것이다. 그렇지만 테이블이 수십, 수백 개가 되면 반드시 누락이 올 수 있는 방법이다.
- @MappedSuperClass : 속성만 내려서 테이블에서 같이 사용하는 상속
- @PrePersist, @PostPersit, @PreUpdate, @PostUpdate 어노테이션 사용
- @Column(updatable, insertable) 옵션 조절
이런 것을 슬기롭게 해결하기 위해 JPA는 Audit을 위 세 가지 기능으로 스마트하게 도와준다.
@MappedSuperClass
@MappedSuperClass는 상속의 일종이다. 이 어노테이션이 있는 클래스는 엔티티로 사용 되지 않는다. 철저하게 다른 엔티티에서 이 엔티티의 속성을 상속받아, 속성만 사용할 수 있도록 도와준다. 일반적으로 JPA 엔티티의 상속은 자바 객체에서의 상속같은 것이 있기도 하지만, @MappedSuperClass처럼 속성만 상속받아 테이블에서 사용할 수 있도록 도와준다.
@Getter
@MappedSuperclass
public class JpaBaseEntity {
@Column(updatable = false, insertable = true)
private LocalDateTime createdDate;
private LocalDateTime updatedDate;
}
사용을 하기 위해서는 BaseEntity를 하나 만들어주고, @MappedSuperClass 어노테이션을 붙여준다.
public class Member extends BaseEntity{}
그리고 이 속성값을 상속받아 사용할 클래스에서 상속만 받아주면 된다.
이렇게만 해주면 위에서 볼 수 있듯이, @MappedSuperClass의 속성만 상속받은 자식 클래스의 테이블에서 사용하는 것을 볼 수 있다.
@Column 속성 설정
@Column(updatable = false, insertable = true)
private LocalDateTime createdDate;
private LocalDateTime updatedDate;
다음과 같이 @Column에 "updatable", "insertable" 속성을 업데이트 해줄 수 있다. updatable을 true로 하면, update 쿼리에서도 동작이 가능하다는 것을 의미한다. insertable = true, updatable = false로 해두면 최초로 등록은 되지만 수정은 불가능한 것이 보장된다. 따라서 createdDate에 Column 옵션 설정을 할 수 있다.
@PrePersist, @PostPersist, @PreUpdate, @PostUpdate 어노테이션 활용
@PrePersist, @PostPersist, @PreUpdate, @PostUpdate 어노테이션을 활용해서 동작을 정의할 수 있다. 이 어노테이션은 이름에서 알 수 있듯이, 각각 EntityManager가 Persist를 하거나 Update를 할 때, 그 동작 전후로 어떤 행동을 할지를 정의하는 것이다.
@PrePersist
public void prePersist() {
LocalDateTime now = LocalDateTime.now();
createdDate = now;
updatedDate = now;
}
@PreUpdate
public void preUpdate() {
updatedDate = LocalDateTime.now();
}
따라서 위 코드처럼 처음 엔티티가 등록되는 Persist 시점에는 createTime, UpdatedTime을 모두 등록해주고, 엔티티가 수정된 Update 쿼리에서는 @Preupdate에서 updatedTime만 설정해서 Audit을 할 수 있게 된다.
스프링 데이터 JPA가 지원하는 자동 Audit 기능
위에서 이야기 한 Audit 기능은 순수 JPA가 지원하는 기능이다. 스프링 데이터 JPA는 여기서 조금 더 자동화 된 기능을 지원한다.
// 스프링 데이터 JPA Audit
@EntityListeners(AuditingEntityListener.class)
@Getter
@MappedSuperclass
public class BaseEntity {
// 스프링 데이터 JPA Audit
@CreatedDate
@Column(updatable = false)
private LocalDateTime createdDate;
// 스프링 데이터 JPA Audit
@LastModifiedDate
private LocalDateTime lastModifiedDate;
// 스프링 데이터 JPA Audit
@CreatedBy
@Column(updatable = false)
private String createdBy;
// 스프링 데이터 JPA Audit
@LastModifiedBy
private String lastModifiedBy;
}
스프링 데이터 JPA의 자동 Audit 기능을 사용하기 위해서는 먼저 @MappedSuperClass 어노테이션이 붙은 클래스에 @EntityListeners(AuditingEntityListner.class)라는 어노테이션을 달아준다. 이 어노테이션이 달리면, 이 어노테이션 아래에 있는 필드의 특정 Audit 컬럼에 이벤트가 있을 때마다 Audit이 반영될 준비를 해준다.
이후, 등록 시간과 수정 시간은 @CreatedDate, @LastModifedDate 어노테이션을 필드 위에 달아주기만 하면 된다. 등록사와 수정자는 @CreatedBy, @ModifiedBy 어노테이션을 달아주면 된다. 이렇게 어노테이션을 달아주면, 이 엔티티를 상속받아 사용하는 자식 클래스에서 Audit이 발생하면 자동적으로 이 Audit을 해준다.
이 때, 등록자와 수정자에 필요한 값을 넣어주기 위해서는 특정한 인터페이스를 구현해서 스프링 빈으로 등록해줘야한다고 한다. 주로, 스프링 시큐리티의 값을 넣어준다고 하기 때문에 지금 당장은 필요 없을 것 같아 따로 공부하진 않았다.
정리
순수 JPA를 활용한 Audit은 다음 순서대로 한다
- @MappedSuperClass로 Base Entity를 만들어준다.
- Audit 속성을 사용할 클래스들이 Base Entity를 상속받도록 한다
- @MappedSuperClass 내부에서 @PostPersist, @PrePersist, @PostUpdate, @PreUpdate 어노테이션을 활용해 수정, 등록 시에 시간을 바꿀 수 있도록 메서드를 구성한다.
- @MappedSuperClass에서 최초 등록한 시간은 @Column의 속성 값에 수정 불가능을 준다
스프링 Data JPA를 활용한 Audit은 다음 순서대로 한다
- @MappedSuperClass로 Base Entity를 만들어주고, @EntityListeners(AuditingEntityListner.class)를 달아준다.
- Audit 속성을 사용할 클래스들이 Base Entity를 상속받도록 한다
- @MappedSuperClass 내부에 @Column 속성을 주고, @CreatedDate, @UpdatedDate, @LastModifiedBy, @CreatedBy 어노테이션을 달아준다.
'Spring > JPA' 카테고리의 다른 글
JPA : @Repository 어노테이션의 기능 (0) | 2022.02.06 |
---|---|
스프링 Data JPA : 사용자 정의 Repository 만들기 (0) | 2022.02.05 |
JPA : 객체의 영속성 컨텍스트 참조 (0) | 2022.02.05 |
스프링 JPA : Open Session In View (0) | 2022.01.17 |
JPA : Order와 관련된 API 구현하기 (0) | 2022.01.15 |