기록하는 습관

Spring - JPA (3) update 쿼리와 영속성 컨텍스트 본문

개발/Spring

Spring - JPA (3) update 쿼리와 영속성 컨텍스트

로그뉴 2022. 7. 12. 13:38

기본적으로 JPA에서 update를 하려면 다음과 같이 진행하는 것이 일반적이다.

@Modifying
@Query("UPDATE Post p SET p.title = :title WHERE p.id = :id")
int updateTitle(String title, Long id);

 

예제 step

  1. 저장 - Post 객체 save()
  2. 수정 - post.updateTitle("변경진행")
  3. 조회 - findById(post.getId())

 

위와 같은 코드를 짰을 때, 발생하는 문제점은 다음과 같다.

updateTitle 함수 실행 후, 객체를 확인하면 값이 변경되어 있지 않다.

  1. findById()를 호출시, select 쿼리는 수행되지 않는다. 
    1. → 이유: findById()는 DB를 확인하기 전에 우선적으로 영속성 컨텍스트(1차 캐시)에 찾으려는 Id의 엔티티가 존재하는지를 확인하기 때문.
  2. findById() 호출전에 post.save()를 호출했는데 이 때, 영속성 컨텍스트에 post가 저장 되었음.
    1. 따라서, 영속성 컨텍스트에 있는 p를 그대로 반환하게 되고, 이 때의 p의 title 값은 수정 전 값이 된다.

 

영속성 컨텍스트에 있는 값이 반환되는 이유

  • 트랜잭션이 아직 끝나지 않고 캐시가 비워지지 않았기 때문에 spring 객체가 PersistenceContext에 그대로 있어서 spring 객체는 계속해서 persist 상태의 객체임
  • persist 상태의 객체는 1차 캐시 즉, PersistenceContext가 관리하고 있음
  • 그 상태 에서 find를 하면 DB를 가지 않음. 자기자신이 캐싱하고 있던 것을 그대로 가지고 옴.
  • 따라서, 데이터베이스의 Update 쿼리가 발생했지만 spring 객체는 persist 상태의 객체이므로 캐시에 남아있었기 떄문에 수정된 값을 확인할 수 없는 것.

 

 

해결법

  1. @Modifying(clearAutomatically = true, flushAutomatically = true) 
    1. persist context에 쌓여있던 캐시를 비워주는 옵션. 권장하지 않음.

 

 

 

Comments