반응형
만약, DB에 Member Table이 있고, Salary라는 컬럼이 존재한다고 가정해보자.
연봉 3000 미만의 member들의 Salary를 수정한다고 가정했을 때, JPA 관점에서는 다음과 같은 순서로 진행될 것이다.
- em.find() OR select 쿼리를 날려 영속성 컨텍스트에 엔티티 저장 후 반환
- 반환 받은 엔티티의 값을 변경한다. -> 영속성 컨텍스트에 반영된다.
- 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 간에 데이터 차이 발생)
해결 방법
- em.refresh() 사용
- 벌크 연산 수행 직후 정확한 salary 엔티티를 사용해야 한다면, em.refresh(salary)를 사용하여 DB에서 salary를 다시 조회한다.
- 벌크 연산 먼저 실행
- 벌크 연산 먼저 실행하고 조회하면 된다. 가장 실용적인 해결책이며, JPA와 JDBC를 함께 사용할 때도 유용하다.
- 벌크 연산 수행 후 영속성 컨텍스트 초기화
- 영속성 컨텍스트에 남아 있는 엔티티를 제거하는 방법이다.
정리
JPA에서 단 건의 데이터의 경우 Dirty Checking을 통해 UPDATE를 수행 하고,
여러 건(대량의 데이터)의 데이터의 경우 벌크 연산(Bulk Operation)을 통해 한 번에 수정하거나 삭제 한다.
참고
https://dev-coco.tistory.com/169
반응형
'Back-end > Spring' 카테고리의 다른 글
[Spring] Docker-Compose를 활용한 CI / CD 구축 (1) | 2025.03.18 |
---|---|
[Spring] com.auth0 vs jsonwebtoken.jjwt (1) | 2025.02.16 |
[Spring] Spring Batch를 활용한 배치 프로세싱 (1) | 2025.01.20 |
[Spring] Private 메서드에 @Transactional 선언 시 트랜잭션이 동작하는가? (0) | 2025.01.16 |
[Spring] Spring Data JPA에서 새로운 Entity인지 판단하는 방법? (1) | 2024.12.08 |