[Spring data jpa]벌크성 쿼리 / @Modifying 어노테이션

김건우·2022년 12월 3일
0

Spring Data JPA

목록 보기
1/11
post-thumbnail

@Modifying

  • @Query어노테이션을 통해 작성된 insert / update/ delete 쿼리에서 사용하는 어노테이션
    다음은 순수 jpa에서 사용한 벌크성 repository
    //단순 jpa 사용 -> age이상인 회원의 나이를 +1 해주는 메소드 
    public int bulkAgePlus(int age) {
        int result = em.createQuery("update Member m set m.age = m.age+1 where m.age >=:age")
                .setParameter("age", age)
                .executeUpdate();
        return result;
    }
  • 기존에 Spring data jpa 를 사용하기전에는 .executeUpdate()라는 메소드를 사용해 주어야 했다.

  • @Modifying 어노테이션은 벌크성 쿼리 메소드에서 excuteUpdate()의 역할을 해준다.

    excuteUpdate()의 메소드는 데이터 조회(select)를 제외한데이터를 추가(Insert), 삭제(Delete), 수정(Update)하는 SQL 문을 실행

  • 기본적으로 jpaRepository에서 제공하는 메서드나 메서드 네이밍으로 만들어진 쿼리에는 적용되지 않는다.

  • clearAutoMatically, flushAutomatically 속성이 존재하며 주로 벌크연산과 같이 이용된다.

다음은 Spring data jpa를 사용한 Repository 메소드

@Query("update Member m set m.age = m.age+1 where m.age >=:age")
    int bulkAgePlus(@Param("age") int age);

만약 이 Spring data jpa를 사용한 벌크성 쿼리 위에 @Modifying 어노테이션을 붙여주지 않는다면 다음과 같은 예외가 발생한다.

org.hibernate.hql.internal.QueryExecutionRequestException: Not supported for DML operations

벌크성 쿼리를 실행한 다음에 영속성 컨텍스트에 과거 값이 남아서 문제가 될 수 있다. 만약 다시 조회해야한다면 반드시 영속성 컨텍스트를 초기화해야하는데 @Modifying에는 다음과 같은 속성이 존재한다.

ClearAutomatically 속성

JPA에서 1차 캐시는 DB의 접근 횟수를 줄여주고 다양한 성능 개선의 효과를 가져다주지만 @Modifying과 @Query를 이용한 벌크 연산에서는 이 기능때문에 예측 불가능한 결과가 나올 수 있다.
이제 할말이 굉장히 중요한 말이다.
JPA에서 조회를 실행할 때 1차 캐시를 확인해서 해당 엔티티가 1차 캐시에 존재한다면 DB에 접근하지 않고, 1차캐시의 엔티티를 반환한다. 하지만 벌크연산은 1차 캐시를 포함한 영속성 컨텍스트를 무시하고 바로 QUERY를 실행하기 때문에 영속성 컨텍스트는 데이터 변경을 알 수 없다. 즉, 벌크연산을 실행할 떄 싱크가 맞지 않게된다.

이 문제를 해결하기위해 @Modigying어노테이션은 ClearAutomatically라는 속성이 존재하는 것이다. defalt가 False인 이 속성을 true로 변경해준다면 벌크연산 직후 자동으로 영속성 컨텍스트를 clear해준다 영속성 컨텍스트를 Clear해준다면 조회를 실행할 때 이미 update결과가 진행되어진 DB를 조회하기 때문에 데이터의 동기화문제를 해결할 수 있다.


    @Modifying(clearAutomatically = true) //@Modifying 이것이 jpa에서 .excuteUpdate() 를 해준다.
    @Query("update Member m set m.age = m.age+1 where m.age >=:age")
    int bulkAgePlus(@Param("age") int age);
   
   //clearAutomatically = true 속성은 벌크성 쿼리가 실행한다음에  em.clear()를 해준다.(영속성 컨텍스트 clear)
profile
Live the moment for the moment.

0개의 댓글