반응형
모든 엔티티를 대상으로 언제 어떤 사용자가 삭제를 요청했는지 모두 로그를 남겨야 하는 요구사항이 있다고 가정하자. 이때 애플리케이션 삭제 로직을 하나씩 찾아서 로그를 남기는 것은 너무 비효율적이다.
JPA 리스너 기능을 사용하면 엔티티의 생명주기에 따른 이벤트를 처리할 수 있다.
이벤트 종류
- PostLoad
엔티티가 영속성 컨텍스트에 조회된 직후 또는 refresh를 호출한 후(2차 캐시에 저장되어 있어도 호출된다) - PrePersist
persist() 메소드를 호출해서 엔티티를 영속성 컨텍스트에 관리하기 직전에 호출된다. 식별자 생성 전략을 사용한 경우 엔티티에 식별자는 아직 존재하지 않는다. 새로운 인스턴스를 merge 할 때도 수행된다. - PreUpdate
flush나 commit을 호출해서 엔티티를 데이터베이스에 수정하기 직전에 호출된다. - PreRemove
remove() 메소드를 호출해서 엔티티를 영속성 컨텍스트에서 삭제하기 직전에 호출된다. 또한 삭제 명령어로 영속성 전이가 일어날 때도 호출된다. orphanRemoval에 대해서는 flush나 commit 시에 호출된다. - PostPersist
flush나 commit을 호출해서 엔티티를 데이터베이스에 저장한 직후에 호출된다. 식별자가 항상 존재한다. 참고로 식별자 생성 전략이 ICENTITY면 식별자를 생성하기 위해 persist()를 호출하면서 데이터베이스에 해당 엔티티를 저장하므로 이때는 persist()를 호출한 직후에 바로 PostPersist가 호출된다. - PostUpdate
flush나 commit을 호출해서 엔티티를 데이터베이스에 수정한 직후에 호출된다. - PostRemove
flush나 commit을 호출해서 엔티티를 데이터베이스에 삭제한 직후에 호출된다.
이벤트 적용 위치
이벤트는 엔티티에서 직접 받거나 별도의 리스너를 등록해서 받을 수 있다.
- 엔티티에 직접 적용
- 별도의 리스너 등록
- 기본 리스너 사용
엔티티에 직접 적용
@Entity
public class Product {
@Id
@GeneratedValue
public Long id;
private String name;
@PrePersist
public void prePersist() {
System.out.println("prePersist id = " + id);
}
@PostPersist
public void postPersist() {
System.out.println("postPersist id = " + id);
}
@PostLoad
public void postLoad() {
System.out.println("postLoad id = " + id);
}
@PreRemove
public void preRemove() {
System.out.println("preRemove id = " + id);
}
@PostRemove
public void postRemove() {
System.out.println("postRemove id = " + id);
}
}
해당 엔티티에 이벤트가 발생할 때마나 어노테이션으로 지정한 메소드가 실행된다.
별도의 리스너 등록
public class ProductListener {
@PrePersist
// 특정 타입이 확실하면 특정 타입을 받을 수 있다.
public void prePersist(Product product) {
System.out.println("prePersist id = " + product.getId());
}
@PostPersist
// 특정 타입이 확실하면 특정 타입을 받을 수 있다.
public void postPersist(Product product) {
System.out.println("postPersist id = " + product.getId());
}
}
@Entity
@EntityListeners(ProductListener.class)
public class Product {
@Id
@GeneratedValue
public Long id;
private String name;
// Get ...
}
리스너는 대상 엔티티를 파라미터로 받을 수 있다. 반환 타입은 void로 설정해야 한다.
기본 리스너 사용
모든 엔티티의 이벤트를 처리하려면 기본 리스너를 등록하면 된다.
아래 xml 형태로 META-INF/orm.xml에 등록이 가능하다.
여러 리스너를 등록했을 때 이벤트 호출 순서는 다음과 같다.
- 기본 리스너
- 부모 클래스 리스너
- 리스너
- 엔티티
더 세밀한 설정
더 세밀한 설정을 위한 어노테이션도 있다.
@Entity
@EntityListeners(ProductListener.class)
@ExcludeDefaultListeners
@ExcludeSuperclassListeners
public class Product extends ProductParent {
@Id
@GeneratedValue
public Long id;
private String name;
}
- @ExcludeDefaultListeners : 기본 리스너 무시
- @ExcludeSuperclassListeners : 상위 클래스 이벤트 리스너 무시
이벤트를 잘 활용하면 대부분의 엔티티에 공통으로 적용하는 등록 일자, 수정 일자 처리와 해당 엔티티를 누가 등록하고 수정했는지에 대한 기록을 리스너 하나로 처리할 수 있다.
반응형
'JPA' 카테고리의 다른 글
JPA 예외 처리 (0) | 2022.01.24 |
---|---|
엔티티 그래프로 연관관계 조회 하기 (0) | 2022.01.21 |
@Converter를 이용해 데이터를 변환해서 저장하고 가져오기 (0) | 2022.01.20 |
엔티티가 준영속 상태에서 생기는 문제점 (0) | 2022.01.20 |
트랜잭션 범위의 영속성 컨텍스트 (0) | 2022.01.20 |