삽질 주도 개발
article thumbnail

JPA를 사용하다가 준영속 상태인 detach와 엔티티를 제거하는 remove의 실제 동작을 확인해보며 엔티티 매니저의 관리 범위 그리고 1차 캐시의 상태를 예상해보려고 합니다.

 

 

준영속 상태

영속성 컨텍스트에 의해 관리되다가 detach, 떨어져 버린 상태를 의미합니다.

 

즉, 트랜잭션 내에서 영속성 컨텍스트가 엔티티의 영속성을 관리해주는데, 더 이상 관리하지 않게 됩니다.

 

그렇다면 JPA의 1차 캐시, 쓰기 지연 SQL 저장소를 사용할 수 없게 되는데요. 특히, 쓰기 지연 SQL 저장소를 사용하지 못하게 되면 commit()을 하더라도 쓰기 지연 저장소에서 관리되지 않으니 엔티티에 대해 flush가 되지 않습니다.

Member member = new Member();
member.setUsername("woogie");
em.persist(member);
em.detach(member);

transaction.commit(); 

// 아무 쿼리도 실해되지 않는다.

 

조금 더 명확히 보기 위해 다음과 같이 작성해보았습니다.

결과를 보면 detach() 전에는 영속 상태라는 것을 확인할 수 있지만, detach 후에는 commit을 해도 member는 영속성 컨텍스트에서 제외됐기 때문에 실제 DB에 반영이 되지 않습니다. 그리고 detach 후에 find를 하면 1차 캐시에도 없고, DB를 봐도 없으니 null의 결과값을 받는다.

 

개발자가 준영속 상태를 만들 일이 있기야 할까라는 생각이 들기도 합니다. 사실 delete 관련 처리가 어떻게 되는지 궁금해서 detach와 비교를 하다가 작성하게 되었습니다.

 

 

merge로 준영속 상태의 엔티티를 다시 영속 상태를 만들 수 있지만, 오늘의 목표와는 다르기에 다른 포스트에서 다뤄보도록 하겠습니다.

 

 

삭제 상태

영속성 컨텍스트와 데이터베이스에서 삭제된 상태라고 합니다.

 

persist(), find()로 영속성 컨텍스트의 동작 과정을 알게 되었는데, remove()로 영속성 컨텍스트의 상태를 확인해보고 싶었습니다.

결과를 보면 영속성 컨텍스트에서 쓰기 지연 SQL 저장소에서 쿼리가 잘 실행되어 반영되는 모습을 볼 수 있습니다.

 

이번에도 더 명확히 보기 위해서 다음과 같이 작성해보았습니다.

1차 캐시에서 사라졌기에 select 쿼리가 실행이 될거라고 예상을 했지만 실행되지 않았습니다. 즉, 1차 캐시에 있는 값을 그대로 가져왔다는 뜻으로 받아들여지는데요.

 

아주 주관적인 생각으로는 em.persist(member) 후에 아래와 같이 1차 캐시에 저장이 될 것입니다.

ID ENTITY
1 Member("woogie)

em.remove(member)이 다음과 같이 1차 캐시의 상태가 다음과 같이 변경된다면 쿼리가 실행되지 않는다는 것에 이해가 됩니다.

ID ENTITY
1 null

 

김영한님의 '자바 ORM 표준 JPA 프로그래밍'
remove()는 호출하는 순간 영속성 컨텍스트에서 제거된다. 

책을 보면서 위와 같은 내용을 읽었는데, 이번 결과로 인해 remove에 대한 동작에 대해서 궁금증이 생기게 되었습니다.

 

검색 능력이 부족한지 대부분 같은 내용만 나와서 이 궁금증을 해결주실 분이 있다면 공유 부탁드리겠습니다 :)