Spring/자바 ORM 표준 JPA 프로그래밍

[Spring Data JPA] 2-3. 벌크성 수정 쿼리

kyung.Kh 2024. 9. 3. 01:59

JPA는 엔티티를 조회한 뒤, commit 시점에 더티체킹을 통해 수정된 값이 있다면, update 쿼리를 날린다. 즉, 엔티티마다 각각 더티체킹을 하여 update를 각각 날린다.(JPA의 수정)

하지만, 많은 데이터를 변경해야 하는 경우, 위 방식은 성능이 좋지 않다. 따라서 DB에 한 번의 update 쿼리를 날리는 것이 보다 효과적이다.(벌크성 수정 쿼리)

순수 JPA를 사용한 벌크성 수정 쿼리

public int bulkAgePlus(int age) {
    return em.createQuery("update Member m set m.age = m.age + 1 where m.age >= :age")  // 이 조건에 만족하는 것들은 모두 +1이 됨
            .setParameter("age", age)
            .executeUpdate();  // update된 행의 개수 -> 변경된 개수
}

Spring Data JPA를 사용한 벌크성 수정 쿼리

@Modifying  // 이게 없으면 result list나 single result 같은걸 호출한다.
//@Modifying(clearAutomatically = true) // 기본값: false
@Query("update Member m set m.age = m.age + 1 where m.age >= :age")
int bulkAgePlus(@Param("age") int age);

반드시 @Modifying을 추가해줘야 한다. 이는 JPA의 excuteUpdate를 실행하는 것으로 추가하지 않으면 getResultList, getSingleResult를 호출하게 된다. 만약 @Modifying(clearAutomatically = true)를 추가하면 벌크성 쿼리를 실행하고 나서 영속성 컨텍스트를 초기화한다.(em.clear()을 자동으로 해준다)

JPA에서 벌크성 수정 쿼리 유의사항

문제점

JPA는 영속성 컨텍스트로 엔티티가 모두 관리된다. 하지만 벌크 연산은 영속성 컨텍스트를 무시하고 바로 쿼리를 DB로 날려버린다.

이렇게 되면 영속성 컨텍스트에 있는 엔티티의 상태와 DB에 있는 엔티티의 상태가 달라질 수 있다.

이는 영속성 컨텍스트에는 update되기 전의 값이 있을 것이고, DB에는 update된 후의 값이 있을 것이기 때문이다.

권장하는 해결 방안

벌크 연산 이후에는 영속성 컨텍스트를 반드시 초기화(em.flush(), em.clear()) 해야 한다.

초기화 한 후, 다시 엔티티를 DB에서 조회해서 영속성 컨텍스트에 담아야 한다.


[출처]

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EB%8D%B0%EC%9D%B4%ED%84%B0-JPA-%EC%8B%A4%EC%A0%84 → 이 글은 김영한님의 "실전! 스프링 데이터 JPA" 강의 중 5장을 듣고 정리한 내용입니다.

728x90