본문 바로가기
자바/JPA

[JPA/Java] JPQL 벌크 연산

by drCode 2023. 5. 11.
728x90
반응형

재고가 10개 미만인 모든 상품의 가격을 10% 올리려면 어떻게 해야할까?

 

JPA 변경 감지 기능으로 실행하려면 너무 많은 SQL이 실행되어야 한다.

 (1) 재고가 10개 미만인 상품을 리스트로 조회한다.

 (2) 상품 엔티티의 가격을 10% 증가한다

 (3) 트랜잭션 커밋 시점에 변경감지가 동작한다.

 

변경된 데이터가 100건이라면 100번의 UPDATE SQL이 실행될 것이다.

 

벌크 연산은 쿼리 한 번으로 여러 테이블 로우를 변경한다(엔티티)

 

executeUpdate()의 결과는 영향받은 엔티티의 수를 반환하는데, UPDATE, DELETE 쿼리를 지원한다

INSERT(insert into .. select, 하이버네이트 지원)

 

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("teamA");
em.persist(teamA);

Team teamB = new Team();
teamB.setName("teamB");
em.persist(teamB);

Member member = new Member();
member.setUsername("회원1");
member.setAge(0);
member.setTeam(teamA);
member.setType(MemberType.ADMIN);
em.persist(member);

Member member2 = new Member();
member2.setUsername("회원2");
member2.setAge(0);
member2.setTeam(teamA);
member2.setType(MemberType.USER);
em.persist(member2);

Member member3 = new Member();
member3.setUsername("회원3");
member3.setAge(0);
member3.setTeam(teamB);
member3.setType(MemberType.USER);
em.persist(member3);

 

// FLUSH 자동 호출
int resultCount = em.createQuery("update Member m set m.age = 20")
                    .executeUpdate();
                    
em.clear(); /// 영속성 컨텍스트를 초기화해줘야 한다. 그렇지 않으면 DB에만 저장되고, 1차 캐시에는 저장되지 않는다.

Member findMember = em.find(Member.class, member.getId());
System.out.println("findMember = " + findMember.getAge());
System.out.println("resultCount = " + resultCount);

실행 결과

em.clear(); 까지 해줘야, 영속성 컨텍스트까지 초기화 되어야 데이터를 메모리에서도 가져와서 사용할 수 있다.

728x90
반응형

댓글