안녕세계

[Spring] @PostPersist와 TransactionPhase.AFTER_COMMIT 본문

[Spring] @PostPersist와 TransactionPhase.AFTER_COMMIT

Junhong Kim 2024. 6. 30. 23:34
728x90
반응형

@PostPersist@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)는 모두 Spring에서 트랜잭션 관련 이벤트를 처리하는데 사용됩니다. 두 어노테이션은 동작 시점과 사용 용도가 다르므로 차이를 이해하고 사용해야합니다. 본 포스팅에서는 두 어노테이션의 차이점에 대해 알아봅니다.
 

@PostPersist

  • 동작 시점
    • 엔티티가 영속성 컨텍스트에 저장된 직후 호출됩니다. 즉, persist 메서드가 호출된 후를 의미합니다.
    • 데이터베이스에 INSERT 연산이 수행된 후 호출되며, 트랜잭션 commit이 되기 전에 호출됩니다.
fun main() {
    val emf: EntityManagerFactory = Persistence.createEntityManagerFactory("hello")
    val em: EntityManager = emf.createEntityManager()

    val myEntity = MyEntity(name = "kim")
    em.transaction.begin()
    em.persist(myEntity)
    
    println("=========before commit======")
    em.transaction.commit()
    println("=========after commit======")

    em.close()
    emf.close()
}

---

@PrePersist entity: kim
Hibernate: 
    /* insert for
        hellojpa.MyEntity */insert 
    into
        MyEntity (name, id) 
    values
        (?, default)
@PostPersist entity: kim
=========before commit======
=========after commit======
  • 사용 방법
    • JPA 엔티티 클래스에 직접 정의합니다.
    • @EntityListeners를 사용하여 JPA 엔티티 생명 주기 이벤트를 처리할 수 있습니다.
      • 엔티티 리스너는 엔티티의 상태 변화에 따라 특정 콜백 메서드를 호출하여 다양한 작업을 할 수 있습니다..
  • 용도
    • 엔티티가 영속성 컨텍스트에 추가된 후 후속 작업을 수행하기 위해 사용됩니다.

JPA entity 클래스에 직접 정의

@Entity
class MyEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    val id: Long? = null,
    val name: String

    @PrePersist
    fun prePersist() {
        println("@PrePersist entity: " + this);
    }

    @PostPersist
    fun postPersist() {
        println("@PostPersist entity: " + this);
    }
}

 
@EntityListeners 사용

@EntityListeners(MyEntityListener.class)
@Entity
class MyEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    val id: Long? = null,
    val name: String
}

class MyEntityListener {

    @PrePersist
    fun prePersist(entity: MyEntity) {
        println("@PrePersist entity: " + entity.name);
    }

    @PostPersist
    fun postPersist(entity: MyEntity) {
        println("@PostPersist entity: " + entity.name);
    }
}

 
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)

  • 동작 시점
    • 트랜잭션이 commit 된 후 호출됩니다.
  • 사용 위치
    • Spring Bean 클래스에 사용합니다.
      • @TransactionalEventListener를 사용하려면 해당 클래스가 Spring 빈으로 등록되어야 합니다.
  • 용도
    • 트랜잭션 commit이 완료된 후 이벤트를 수신하여 작업을 처리하기 위해 사용됩니다.
data class MyEvent(val entityId: Long)

@Entity
data class MyEntity(
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    val id: Long? = null,
    val name: String
)

@Service
class MyService(
    @Autowired private val entityManager: EntityManager,
    @Autowired private val eventPublisher: ApplicationEventPublisher
) {

    @Transactional
    fun saveEntity(name: String) {
        val entity = MyEntity(name = name)
        entityManager.persist(entity)
        
        // 트랜잭션 내에서 이벤트 발행
        eventPublisher.publishEvent(MyEvent(entity.id!!))
    }
}

@Component
class MyEventListener {

    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    fun handleAfterCommit(event: MyEvent) {
        // 트랜잭션이 커밋된 후에 실행되는 로직
        println("Transaction has been committed. Entity ID: ${event.entityId}")
    }
}

 
Q1) @PostPersist가 호출되는 시점을 commit 후로 변경할 수 있을까?

@PostPersist는 JPA entity의 라이프사이클 콜백 메서드로, 엔티티가 영속성 컨텍스트에 추가된 후에 호출되기 때문에 트랜잭션 commit 후로 변경할 수 없습니다. 트랜잭션 commit 후에 작업을 처리하기 위해서는 @TransactionEventListener를 사용해야합니다.
 

Q2) @TransactionEventListener를 사용하여 commit 전에 이벤트를 처리할 수 있을까?

@TransactionalEventListener는 phase 속성을 사용하여 트랜잭션 이벤트를 처리할 시점을 지정할 수 있습니다. commit 전에 이벤트를 처리하려면 BEFORE_COMMIT 옵션을 사용하면 됩니다. 더 자세한 내용은 [Spring] EventListener vs TransactionalEventListener 포스팅에서 확인하실 수 있습니다.
 

728x90
반응형
Comments