@Modifying 이란?
Spring Data JPA에서 사용되는 어노테이션으로, @Query 어노테이션을 통해 작성되어 변경이 일어나는 쿼리(Insert, Update, Delete)를 실행할 때 사용된다.
@Modifying을 변경이 일어나는 쿼리와 함께 사용해야 JPA에서 변경 감지와 관련된 처리를 생략하고 더 효율적인 실행이 가능하다.
JPA에서 벌크 연산은 단건 데이터를 변경(더티 체킹)하는 것이 아닌, 여러 데이터에 변경 쿼리를 날리는 작업을 말한다.
@Modifying 어노테이션을 사용하여 벌크 연산을 수행할 수 있다.
예를 들어 게시글 아이디(lostFoundBoardId)를 통해 해당 게시글의 댓글을 모두 삭제하기 위해 벌크 연산을 수행할 수 있다.
@Modifying(clearAutomatically = true)
@Query("delete from Comment c where c.lostFoundBoardId = lostFoundBoardId")
int deleteByIdAndLostFoundBoardId(@Param("lostFoundBoardId")Long lostFoundBoardId);
이렇게 하면, JPA가 데이터베이스에서 해당 게시글에 대한 모든 댓글을 한 번에 지우는 쿼리를 실행하고 삭제된 행의 개수를 반환한다.
이 방식을 통해 일괄 처리를 할 때 효율적인 성능 개선을 얻을 수 있다.
@Modifying 사용 시 주의할 점
1. 변경 쿼리 동기화 문제
JPA에서는 1차 캐시라는 기능이 있다. 1차 캐시를 간단하게 설명하자면 영속성 컨텍스트에 있는 1차 캐시를 통해 엔티티를 캐싱하고, DB 접근 횟수를 줄임으로써 성능을 개선한다.
그런데 @Modifying과 @Query를 사용한 벌크 연산에서 1차 캐시와 관련하여 문제가 발생한다.
JPA에서 조회를 실행할 때 1차 캐시를 확인해서 해당 엔티티가 1차 캐시에 존재한다면 DB에 접근하지 않고, 1차 캐시에 있는 엔티티를 반환한다. 하지만 벌크 연산은 1차 캐시를 포함한 영속성 컨텍스트를 무시하고 바로 Query를 실행하기 때문에 영속성 컨텍스트는 데이터 변경을 알 수가 없다.
즉 벌크 연산 실행 시 1차 캐시(영속성 컨텍스트)와 DB의 데이터 싱크가 맞지 않게 된다.
만약 벌크 연산을 실행하고 다시 해당 데이터를 조회하면 영속성 컨텍스트에 과거 값이 남아 문제가 발생한다.
이 경우 영속성 컨텍스트를 비워주는 작업이 필요하다.
@Modifying의 clearAutomatically=true 속성을 사용해 변경 후 자동으로 영속성 컨텍스트를 초기화할 수 있다.
해당 속성을 추가하게 되면, 조회를 실행할 때 1차 캐시에 해당 엔티티가 존재하지 않기 때문에 DB 조회 쿼리를 실행하게 된다. (데이터 동기화 문제 해결)
@Modifying(clearAutomatically = true)
2. 트랜잭션 관리
@Modifying 어노테이션은 기본적으로 @Transactional과 함께 사용된다. 변경 작업은 트랜잭션 내에서 실행되어야 한다. 완료되지 않은 변경 작업이 여러 작업에 영향을 줄 수 있기 때문이다. 이를 통해 데이터베이서에 대한 변경 작업을 수행할 때 원자성, 일관성, 독립성, 지속성을 보장할 수 있게 된다.
댓글