JPA에서 제공하는 Entity Listener의 종류와 쓰임에 대해서 정리해보았습니다.
Entity Listener는 JPA가 동작하는 이벤트 구간을 관찰하고 있다가 발생하면 특정 동작을 실행하는 메소드라고 볼 수 있습니다.
Entity Listener Annotation
@PrePersist: entity manager persist operation(insert 작업)가 실행되기 전
@PreRemove: entity manager remove operation(delete 작업)가 실행되기 전
@PreUpdate: database의 update 작업이 실행되기 전
@PostPersist: database의 insert 작업이 실행된 이후
@PostRemove: database의 delete 작업이 실행된 이후
@PostUpdate: database의 update 작업이 실행된 이후
@PostLoad: select 조회가 된 직후
즉 Entity Listener는 데이터 베이스의 DML 쿼리 동작의 전후 시점에 이벤트를 발생시킬 수 있게 해준다.
예를 들면, insert 직전에 생성일을 만들어주거나, update 직후에 수정일을 만들어서 쿼리에 해당 값을 넣어주는 것이다.
주의할 점은 같은 Entity 내에 같은 Entity Listener를 만들면 안됩니다!!
Entity Listener를 Entity 내부에 마다 직접적으로 다 선언해서 사용하는 것이 아니라,
공통 기능으로 사용할 수 있습니다.
JPA Entity 프로퍼티를 공통적으로 사용하면서 해당 프로퍼티에 공통적으로 Entity Listener를 구현함으로써, 코드를 좀 더 간결하고 일괄되게 작성할 수 있습니다.
이러한 기능을 구현하기 위해서는 클래스 상속 외에도 몇가지 어노테이션을 사용해서 구현해야합니다.
Entity Listener 단일 클래스 내부에서 구현
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Data
@NoArgsConstructor
@Entity
public class User {
@Id
@GeneratedValue
private Long id;
private Long userId;
private String name;
private String email;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
@PrePersist
public void prePersist() {
System.out.println(">>> prePersist");
}
@PostPersist
public void postPersist() {
System.out.println(">>> postPersist");
this.createdAt = LocalDateTime.now();
this.updatedAt = LocalDateTime.now();
}
@PreUpdate
public void preUpdate() {
System.out.println(">>> preUpdate");
}
@PostUpdate
public void postUpdate() {
System.out.println(">>> postUpdate");
this.updatedAt = LocalDateTime.now();
}
}
해당 클래스 내부에서만 Entity Listener를 사용할 경우,
클래스 내부에 Entity Listener 어노테이션을 사용하여 메소드로 구현하면 됩니다.
JPA의 Auditing 기능
JPA의 Auditing 기능을 사용하서 Entity Listener를 공통 모듈로 구현할 수 있습니다.
Audit은 주로 DB값이 변경했을 때 누가 값을 변경했고, 언제 변경했는지 Audit(감사)하는 용도로 합니다.
Spring Data JPA는 @CreatedDate, @LastModifiedDate, @CreatedBy, @LastModifiedBy 와 같은 어노테이션을 제공합니다.
Auditing 기능을 사용해서 Entity Listener를 공통 클래스로 구현하기 위해서는 몇 가지 작업이 필요합니다.
@SpringBootApplication
@EnableJpaAuditing
public class FastJpaApplication {
public static void main(String[] args) {
SpringApplication.run(FastJpaApplication.class, args);
}
}
우선 메인 클래스에 @EnableJpaAuditing를 선언합니다.
package com.example.bookmanager.domain;
import lombok.Data;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import java.time.LocalDateTime;
@Data
@MappedSuperclass // 해당 클래스의 필드를 상속받는 class의 Entity 컬럼으로 추가시키겠다는 뜻
@EntityListeners(value = AuditingEntityListener.class)
public class BaseEntity {
@CreatedDate
private LocalDateTime createdAt;
@LastModifiedDate
private LocalDateTime updatedAt;
}
상속받아 사용할 공통 프로퍼티를 담은 클래스를 만들어줍니다.
@MappedSuperclass 어노테이션은 해당 클래스를 상속받는 자식클래스에 부모 프로퍼티를 Entity 컬럼으로 사용할 수 있게 하는 기능을 합니다.
@EntityListeners(value = AuditingEntityListener.class) 어노테이션은 다른 클래스에 등록되어 있는 Entity listener를 사용하게 합니다.
사용자 Entity listener가 존재한다면, @EntityListeners의 value 값으로 등록해서 사용하면 됩니다.
여기에서는 Auditng에 정의된 Entity listener를 사용함으로, AuditingEntityListener.class를 @EntityListeners의 value 값으로 지정해주시면 됩니다.
공통 클래스 내에 프로퍼티에 Autiting 어노테이션을 사용합니다.
날짜는 생성해주는 @CreatedDate, @LastModifiedDate 를 사용하면 insert, update 시 자동으로 현재 날짜를 생성해줍니다.
@CreatedBy, @LastModifiedBy 는 각각 생성자, 수정자를 등록할 수 있게 하는 어노테이션입니다.
@CreatedBy, @LastModifiedBy 어노테이션은 주로 스프링 시큐리티의 Principal과 함께 사용합니다.
이후 포스팅에 스프링 시큐리티와 같이 다루어 보기로 하겠습니다.
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Data
@ToString(callSuper = true) // 상속 받는 클래스의 프로퍼티를 정상적으로 등록하기 위한 추가 처리
@EqualsAndHashCode(callSuper = true) // 상속 받는 클래스의 프로퍼티를 정상적으로 등록하기 위한 추가 처리
@NoArgsConstructor
@Entity
public class User extends BaseEntity {
@Id
@GeneratedValue
private Long id;
private Long userId;
private String name;
private String email;
}
마지막으로 공통 기능을 사용할 본 Entity에서 공통 Entity Listener를 구현한 BaseEntity 클래스를 상속받으면 됩니다.
주의할 점은 상속받은 프로퍼티를 정상적으로 사용하기 위해서
@ToString(callSuper = true), @EqualsAndHashCode(callSuper = true) 와 같은 추가 처리를 꼭 하셔야합니다.
이로써, BaseEntity 클래스에 구현한 createdAt, updatedAt 프로퍼티를 정상적으로 사용할 수 있게 되며, 해당 프로퍼티에 구현되어있는 Autiting Entity Listener를 사용할 수 있게 됩니다.
Entity Listener 예제에 관해서는 다음 포스팅에서 한번 더 다룰 예정입니다.
여기까지 끊고 마무리하겠습니다.
https://docs.jboss.org/hibernate/core/4.0/hem/en-US/html/listeners.html
Chapter 6. Entity listeners and Callback methods
@PostPersistExecuted after the entity manager persist operation is actually executed or cascaded. This call is invoked after the database INSERT is executed.
docs.jboss.org
https://milenote.tistory.com/79
[ JPA ] 4. Entity Listener
Reference. 한 번에 끝내는 Java/Spring 웹 개발 마스터 초격차 패키지 Online 이전 글 더보기 1. Repository interface 메서드 2. Query Method 정의 및 실습 3, Entity 기본속성 5.5. Entity Listener Listener:..
milenote.tistory.com
https://umanking.github.io/2019/04/12/jpa-audit/
[JPA] Auditing 사용하기
Spring Data JPA의 Audit 기능에 대해서 알아보자.
umanking.github.io
'JPA' 카테고리의 다른 글
JPA - 트랜잭션 매니저1 개요 (0) | 2022.03.25 |
---|---|
JPA - 트랜잭션 매니저2 독립성(격리) 속성 (0) | 2022.03.25 |
JPA - 연관 관계 (0) | 2022.03.25 |
JPA - Entity의 기본 속성 (0) | 2021.12.03 |
JPA - JPA 관련 용어 소개 (0) | 2021.11.30 |
댓글