본문 바로가기
Spring/JPA

벌크연산(Bulk Operation)

by o3oppp 2024. 1. 17.

기존연산

  • ex) 모든 직원들 연봉 30% 인상
    1. em.find() 메서드를 통해 모든 직원을 리스트로 조회
    2. 직원 엔티티의 연봉을 30% 증가
    3. 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)를 가져옴


해결

  1. 벌크 연산을 먼저 실행
  2. 벌크 연산 후 영속성 컨텍스트 초기화
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)를 새로 가져옴

'Spring > JPA' 카테고리의 다른 글

Named 쿼리  (0) 2024.01.17
페치조인  (0) 2024.01.15
값 타입 컬렉션  (0) 2024.01.02
임베디드 타입  (0) 2023.12.30
영속성 전이  (0) 2023.12.29