기존연산
- ex) 모든 직원들 연봉 30% 인상
- em.find() 메서드를 통해 모든 직원을 리스트로 조회
- 직원 엔티티의 연봉을 30% 증가
- Commit 시점에 변경감지(Dirty Checking)가 일어나며 update 쿼리 실행
- 만약 리스트로 조회된 결과가 몇십만, 몇백만개라면 성능의 문제 발생
- 따라서 벌크연산이 필요
벌크연산(Bulk Operation)
- 쿼리 한 번으로 여러 테이블 로우 변경(엔티티)
- executeUpdate() 메서드를 통해 벌크연산 수행
- executeUpdate()의 결과는 영향받은 엔티티의 수
- UPDATE, DELETE 지원
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();
특징
- 영속성 컨텍스트를 무시하고 데이터베이스에 직접 쿼리
Team teamA = new Team();
teamA.setName("팀A");
em.persist(teamA);
Member member1 = new Member();
member1.setUsername("회원1");
member1.setAge(0);
member1.setTeam(teamA);
em.persist(member1);
em.flush();
em.clear();
int resultCount = em.createQuery("update Member m set m.age = 20")
.executeUpdate();
Member findMember = em.find(Member.class, member1.getId());
System.out.println("member1.getAge() = " + findMember.getAge());
: 영속성 컨텍스트를 무시하고 데이터베이스에 직접 update, getAge()는 영속성 컨텍스트에 있는 데이터(0)를 가져옴
해결
- 벌크 연산을 먼저 실행
- 벌크 연산 후 영속성 컨텍스트 초기화
Team teamA = new Team();
teamA.setName("팀A");
em.persist(teamA);
Member member1 = new Member();
member1.setUsername("회원1");
member1.setAge(0);
member1.setTeam(teamA);
em.persist(member1);
em.flush();
em.clear();
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());
: 영속성 컨텍스트 초기화로 인해 데이터베이스에서 데이터(20)를 새로 가져옴