직접 @Query 파라미터를 통해 데이터를 지우려고 했을 때, 발생한 Error로
쿼리유형이 잘못 동작했을 때 발생하는 타입이다.
이를 해결하기 위해서는 해당 query 메서드를 실행한 곳에 2개의 어노테이션을 추가해줘야 한다
@Modifying
@Transactional
@Modifying 메서드는 Query 어노테이션으로 작성된 insert나 update, delete 쿼리를 사용할 때 필요로 한다
(주로 벌크연산을 하나의 쿼리로 수행할 때 사용 )
벌크 연산 관련 참고자료 :( https://data-make.tistory.com/617 )
@Modifying 공식문서 ( https://docs.spring.io/spring-data/data-jpa/docs/current/api/org/springframework/data/jpa/repository/Modifying.html )
@Modifying 어노테이션으로 들어가보면 2가지 필드 값이 있음을 알 수 있는데, 두 속성 다 기본 값이 false로 되어있다.
첫번째 속성인 flushAuomatically()는 해당 메서드를 사용할 때, 수정 쿼리를 실행하기 전에 기본 지속 컨택스트를 플러시 할 지 여부를 정하는 것이다.
다음 속성인 clearAutomatically()는 수정 쿼리를 실행하기 후에 기본 지속 컨택스트를 지워야 할 지 여부를 정하는 것이다.
이때, 기본값을 사용한다면 영속성 컨택스트의 1차 캐시와 관련된 문제가 발생할 수 있다.
만약 회원 정보를 수정하고, 해당 회원 정보의 정보를 확인해보기 위해서 log나, print 문을 확인했을 때 이 문제점을 발견할 수있는데, DB에서는 수정한 값이 저장되어 있지만, 로그나 출력문을 통해 확인해보면 아직 값이 update가 안됐음을 확인할 수있다.
그 이유는 영속상태인 Persistent에 주목해야하는데, 이 영속 상태에서는 하이버네이트가 한 트랜잭션 내 불필요한 쿼리를 줄여주기에, 이 데이터를 db에서 가지고 오지 않고 이미 영속성 컨택스트(1차 캐시)에 저장된 해당 객체를 가지고 오기 때문이다. 그래서 select 요청을 하더라도 db에 접근하지 않고 컨택스트에 들어있는 인스턴스를 반환한다.
(결론 : 1차 캐시와 DB의 데이터가 불일치 할 수 있음)
그래서 이 기본값을 true로 바꾸게 된다면, select 쿼리가 한번 더 발생하는데, 이는 메소드가 적용된 쿼리 메소드를 실행한 후, 자동으로 영속성 컨택스트를 비우는(clear)하니까, 1차 캐시에 저장된 인스턴스가 없어 DB에 select 요청을 보낸 것이다.
그래서 어노테이션을 사용하게 되면 Jpa Entity의 Life Cycle을 무시하고 쿼리가 실행되서, 영속성 컨텍스트 관리에 주의해야 하는 점이 바로 여기에 있다. (영속성 컨텍스트와 2차 캐시를 무시하고, DB에 직접 쿼리를 날리기 때문이다)
그래서 clearAuthmatically 속성을 true로 변경해줘야 우리가 원하는 결과를 얻을 수 있다는 점을 기억해야한다.
참고 :
https://wildeveloperetrain.tistory.com/142
https://suhwan.dev/2019/02/24/jpa-vs-hibernate-vs-spring-data-jpa/