Back-end/Spring

[Spring] JPA 벌크 연산이란?

류건 2025. 2. 1. 12:29
반응형

만약, DB에 Member Table이 있고, Salary라는 컬럼이 존재한다고 가정해보자.

 

연봉 3000 미만의 member들의 Salary를 수정한다고 가정했을 때, JPA 관점에서는 다음과 같은 순서로 진행될 것이다.

 

 

  1. em.find() OR select 쿼리를 날려 영속성 컨텍스트에 엔티티 저장 후 반환
  2. 반환 받은 엔티티의 값을 변경한다. -> 영속성 컨텍스트에 반영된다.
  3. Commit 시점에 변경 감지(Dirty Checking)가 일어나며 Update 쿼리를 날려 DB에 반영한다.

 

만약, salary를 변경할 member가 80만명이라면?

 

80만번의 더티 체킹이 일어나고, 80만번의 UPDATE 쿼리가 날아갈 것이다...

 

이를 해결할 수 있는 방안이 바로 벌크 연산이다.

 

 

Bulk 연산이란?

 

벌크 연산은 UPDATE, DELETE 문을 지원하며, Hibernate는 INSERT 문도 지원한다.
executeUpdate() 메서드를 통해 벌크 연산을 수행한다.

 

EX>

(여러 건 한 번에 수정) 연봉 3000만 원 미만의 Member의 연봉을 10%만큼 상승

String sql =
	"update Member m" +
        "set m.salary = m.salary * 1.1" +
        "where m.salary < :salary";

int resultCount = em.createQuery(sql)
                    .setParameter("salary", 30000000)
                    .executeUpdate();

 

 

벌크 연산을 사용할 경우 주의사항

※ 벌크 연산은 영속성 컨텍스트를 무시하고 DB에 직접 쿼리 한다는 점을 주의해야 한다.

 

즉, DB에 반영된 변경이 영속성 컨텍스트에는 반영되지 않는다는 말이다.

만약 salary 데이터를 조회 후 벌크 연산을 수행 한다면,
영속성 컨텍스트에 있는 salary와 DB에 있는 salary의 값이 다를 수 있다.
(영속성 컨텍스트와 DB 간에 데이터 차이 발생)

 

해결 방법

  1. em.refresh() 사용
    • 벌크 연산 수행 직후 정확한 salary 엔티티를 사용해야 한다면, em.refresh(salary)를 사용하여 DB에서 salary를 다시 조회한다.
  2. 벌크 연산 먼저 실행
    • 벌크 연산 먼저 실행하고 조회하면 된다. 가장 실용적인 해결책이며, JPA와 JDBC를 함께 사용할 때도 유용하다.
  3. 벌크 연산 수행 후 영속성 컨텍스트 초기화
    • 영속성 컨텍스트에 남아 있는 엔티티를 제거하는 방법이다.

정리

JPA에서 단 건의 데이터의 경우 Dirty Checking을 통해 UPDATE를 수행 하고,
여러 건(대량의 데이터)의 데이터의 경우 벌크 연산(Bulk Operation)을 통해 한 번에 수정하거나 삭제 한다.

 

 

참고

https://dev-coco.tistory.com/169

 

반응형