Spring

[JPA] @PrePersist 에 대해

Bepoz 2021. 8. 3. 23:09

@PrePersist에 대해

@PrePersist 어노테이션은 JPA 엔티티 라이프 싸이클의 콜백을 조종할 수 있게하는 어노테이션이다.

image

다음과 같은 어노테이션들이 있다. 이런 콜백 이벤트들을 사용하는 방법은 엔티티 내부에 직접 메서드를 작성해주는 것과 EntityListener를 만들어 주는 방법이 있다.

image

일반적으로 Auditing을 위해서 EntityLIstener를 사용해본 적이 있을 것이다. 유의할 점은 콜백 메서드들은 void 타입을 리턴해야 한다는 것이다.

내가 엔티티를 만들고 repository의 save메서드를 호출할 때에 @PrePersist가 달린 메서드가 호출이 되고 DB에 insert된 후에 @PostPersist 메서드가 호출이 된다. 만약 내가 @GeneratedValue로 pk를 자동생성한다면 해당 pk는 @PostPersist에서 사용할 수 있을 것이다. 그렇다면 코드로 확인해보자.

image

image

다음과 같이 코드를 작성했다.
@PrePersist가 달린 메서드에 name을 넣어주고 id를 출력했다.
@PostPersist가 달린 메서드에는 id를 출력하는 코드를 넣어주었다.

출력결과를 살펴보자.

image

em.persist(positive)라인에서 null, 쿼리문, 1이 출력된 것을 확인할 수가 있었다.
persist메서드가 호출이되자 @PrePersist가 먼저 콜백되었고 해당 코드내에서 name을 set하고 id를 출력해준 것을 알 수가 있다. id 값은 null로 출력이 되었다. @GeneratedValue를 이용했기 때문이다.

이후 쿼리문이 호출되었는데, name에는 코드에서 설정해둔 bepoz가 쿼리문에 들어가는 것을 확인할 수가 있었다.
@PostPersist가 호출이 되어 id값이 1이 출력되는 것 또한 확인할 수가 있었다.

내가 한 가지 우려했던 점은 기본 키 생성 전략이 IDENTITY이기 때문에 영속성 컨텍스트에 집어넣기 이전에 pk를 얻어오기 위해 insert 쿼리를 날리게 되는데, 이 순서가 @PrePersist보다 먼저 일어날까봐 걱정을 했다.

그렇다면, 내가 의도한 name을 set해주는 코드가 의미가 없어질테니 말이다.(물론, insert가 먼저 일어난 후에 set이 되었다 하더라도 dirty checking으로 db에 값을 넣어줄 수 있긴 했을거임. update 문을 한 번 더 실행해야겠지만)

해당 어노테이션을 나는 엔티티 필드 중에 UUID를 만들어줄 일이 있어서 사용을 해봤는데 이후에 생성자에서 그냥 만들어주는 것으로 바꿔주었다. 엔티티 라이프 싸이클 주기를 컨트롤 할 때에 유용하게 사용할 수 있는 어노테이션인 것 같다.


REFERENCE

https://www.baeldung.com/jpa-entity-lifecycle-events