오봉이와 함께하는 개발 블로그
JPA - 벌크 연산 본문
728x90
벌크 연산
SQL에서 PK를 집어서 하는 Update, Delete를 제외한 모든 Update, Delete문이라고 생각하면 좋다.
- 재고 10개 미만인 모든 상품의 가격을 10% 상승시키려면?
- JPA 변경 감지 기능으로 실행하면 너무 많은 SQL을 실행한다.
- 재고가 10개 미만인 상품을 리스트로 조회
- 상품의 엔티티 가격을 10% 증가
- 트랜잭션 커밋 시점에 변경감지 작동
- 변경된 데이터가 100건이라면 100번의 Update SQL이 실행된다.
예제
- 쿼리 한 번으로 여러 테이블 로우 변경(엔티티)
- executeUpdate()의 결과는 영향받은 엔티티 수 반환
- UPDATE, DELETE 지원
- INSERT(insert into .. select(select한 값을 insert), 하이버네이트에서 지원)지원
String qlString = "update Product p " +
"set p.price = p.price * 1.1 " +
"where p.stockAmount < :stockAmount";
int resultCount = em.createQuery(qlString)
.setParameter("stockAmount", 10)
.executeUpdate();
주의
- 벌크 연산은 영속성 컨텍스트를 무시하고 DB에 직접 쿼리한다.
- 벌크 연산을 먼저 실행
- 영속성 컨텍스트에 작업을 하지 않고 벌크 연산을 실행한다.
- 벌크 연산 수행 후 영속성 컨텍스트를 초기화
- 벌크 연산을 수행하면 어쨌든 쿼리가 나가기 때문에 벌크 연산 전에 강제적으로 flush()가 된다.
- flush()가 됐기 때문에 영속성 컨텍스트를 초기화를 해주면 된다.
- 벌크 연산을 먼저 실행
만약 초기화를 하지 않으면 Member의 이름을 바꿨는데 영속성 컨텍스트에는 바꾸기 전 값이 있고, DB에는 바꾼 뒤 값이 있을 수 있다.
// 모든 Member의 나이는 1로 세팅.
// flush()
int resultCount = em.createQuery("update Member m set m.age = 20").executeUpdate();
System.out.println("member1.getAge() = " + member1.getAge());
System.out.println("member2.getAge() = " + member2.getAge());
System.out.println("member3.getAge() = " + member3.getAge());
// 결과
member1.getAge() = 1
member2.getAge() = 1
member3.getAge() = 1
// 하지만 DB에는 모두 20이라고 바뀜.
초기화를 하면 결과가 달라진다.
// 모든 Member의 나이는 1로 세팅.
// flush()
int resultCount = em.createQuery("update Member m set m.age = 20").executeUpdate();
em.clear();
Member findMember = em.find(Member.class, member1.getId());
System.out.println("findMember = " + findMember.getAge());
// 결과
findMember = 20
참고
Spring Date JPA에서는 Modifying Quries를 통해 벌크 연산을 지원한다.
출처 : 인프런 김영한 지식공유자님의 스프링 부트와 JPA 실무 완전 정복 로드맵 강의
728x90
'BE > JPA' 카테고리의 다른 글
JPA 활용 1 - 엔티티 클래스 개발 (0) | 2022.09.02 |
---|---|
JPA 활용 1 - 도메인 모델과 엔티티 설계 (0) | 2022.09.02 |
JPA - 다형성 쿼리, 엔티티 직접 사용, Named 쿼리 (0) | 2022.07.06 |
JPA - 페치 조인 한계 (0) | 2022.07.05 |
JPA - 페치 조인 기본 (0) | 2022.07.04 |
Comments