Springboot

spring data JPA @Modifying

25G 2023. 8. 17. 19:23

@Modifying

@Query 애노테이션을 사용하면서 데이터에 변경이 일어나는 INSERT, UPDATE, DELETE, DDL 에서 사용합니다. 주로 벌크 연산 시에 사용됩니다.
벌크연산을 할 때는 JPA Entity LifeCycle을 무시하고 쿼리가 실행되기 때문에 해당 애노테이션을 사용할 때는 영속성 컨텍스트 관리에 주의해야 합니다. 앞으로 설명할 clearAutomatically, flushAutomatically를 통해 간단하게 해결할 수 있습니다.

clearAutomatically

@Modifying이 붙은 쿼리메서드 실행 직후 영속성컨텍스트를 clear할 것인지 정한다. defult는 false
쉽게 생각해서 false로 해놓으면 다음과 같은 일이 벌어진다.

  1. A라는 엔티티를 조회 이때 영속성컨택스트가 A라는 엔티티를 1차 캐싱해놓는다
  2. @Modifying을 사용한 쿼리를 이용해서 데이터의 변화를 준다.
  3. 해당 사실을 영속성 컨택스트가 알아차리지 못하고 1.에서 조회했던 캐싱된 정보를 바인딩해준다.(참고로 DB에는 데이터가 변경 돼 있다)
  4. 변경된 값을 바인딩시켜서 값을 핸들링하려는 개발자가 의도한 값이 안나와 개발자는 퇴근할수 없게된다...

위와같은 상황에서는 clearAutomatically = ture 를 사용해주자

flushAutomatically

@Modifying이 붙은 쿼리메서드를 실행하기 전에 영속성 컨택스트의 변경사항을 DB에 flush 할것인지 결정하는 애노테이션
하지만 hibernate의 defult 설정이 AUTO이기때문에 해당 설정을 COMMIT으로 바꿔주지 않으면 해당설정은 의미가 없습니다. AUTO설정이 돼 있으면 @Modifying이 붙은 쿼리메서드를 실행하기 전에 flush가 자동으로 일어나기 때문입니다.
COMMIT으로 설정하는 방법은 application파일에 다음과 같은 설정을 해놓습니다.

spring.jpa.properties.org.hibernate.flushMode=COMMIT

그렇다면 COMMIT으로 설정했다고 치고
해당 설정이 false일때 벌어지는 일

  1. A엔티티 조회
  2. A엔티티의 값 변경
  3. 2에서 변경한 값이 WHERE절에 걸릴것을 예상하고 DELETE쿼리 작성
  4. WHERE절 조건에 걸리지 않아서 아무것도 DELETE되지 않았다
  5. 왜그런지 이해하지 못한 개발자는 퇴근할 수 없게 된다.....

하지만 위와같은 상황은 특별히 위와 같이 application파일에 COMMIT 설정을 해놓지 않으면 해당 설정을 false로 해놓는다고 한들 Hibernate에서 그냥 flush를 해버리기 때문에 자주 생기는 일은 아니겠지만 중요한것은 @Modifying이 붙은 @Query를 사용할때는 해당 메소드가 실행되기전에 영속성컨텍스트의 모든 변경사항에대한 update쿼리가 날라간다는 부분 인것 같습니다.

이 부분을 알고 있어야 해당 메소드를 사용하기전에 날라갈 쿼리를 예상하고 로직을 작성 할 수 있기 때문입니다.