Programming/JPA(KYH)

JPA - 벌크 연산

잇(IT) 2023. 7. 19. 17:26

- 쿼리 한 번으로 여러 테이블 로우 변경(엔티티)

- executeUpdate()의 결과는 영향받은 엔티티 수를 반환한다.

- UPDATE, DELETE를 지원한다.

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

            Team team1 = new Team();
            team1.setName("팀A");
            em.persist(team1);

            Team team2 = new Team();
            team2.setName("팀B");
            em.persist(team2);

            Member member1 = new Member();
            member1.setUsername("회원1");
            member1.setTeam(team1);
            em.persist(member1);

            Member member2 = new Member();
            member2.setUsername("회원2");
            member2.setTeam(team1);
            em.persist(member2);

            Member member3 = new Member();
            member3.setUsername("회원2");
            member3.setTeam(team2);
            em.persist(member3);

            em.flush();
            em.clear();

            int resultCount = em.createQuery("update Member m set m.age = 20")
                    .executeUpdate();

            System.out.println("resultCount = " + resultCount);

- 벌크 연산을 통해 한번에 데이터를 변경할 수 있다.


- * 벌크 연산 주의

1. 벌크 연산은 영속성 컨텍스트를 무시하고 데이터베이스에 직접 쿼리를 날린다.

- > 벌크 연산을 먼저 실행 -> 벌크 연산 수행 후 영속성 컨텍스트 초기

 

            Team team1 = new Team();
            team1.setName("팀A");
            em.persist(team1);

            Team team2 = new Team();
            team2.setName("팀B");
            em.persist(team2);

            Member member1 = new Member();
            member1.setUsername("회원1");
            member1.setTeam(team1);
            em.persist(member1);

            Member member2 = new Member();
            member2.setUsername("회원2");
            member2.setTeam(team1);
            em.persist(member2);

            Member member3 = new Member();
            member3.setUsername("회원2");
            member3.setTeam(team2);
            em.persist(member3);

            //FLUSH가 되면서 위에 쌓여있던 SQL문들이 실행된다.
            int resultCount = em.createQuery("update Member m set m.age = 20")
                    .executeUpdate();

            //3333333
            em.clear();

            //2222222
            Member findMember = em.find(Member.class, member1.getId());
            System.out.println("findMember.getAge() = " + findMember.getAge());
            // 위에 처럼 해도 벌크는 DB에 반영되고 find는 영속성 컨텍스트에서 가져오기 때문에 그대로 0이다.

            //1111111
            System.out.println("resultCount = " + resultCount);

            System.out.println("member1.getAge() = " + member1.getAge());
            System.out.println("member2.getAge() = " + member2.getAge());
            System.out.println("member3.getAge() = " + member3.getAge());
//          애플리케이션에는 0 살 DB에는 20살

1. 현재 member1,2,3이 em.persist를 통해 영속성 컨텍스트에 저장되어 있는 상태다.

2. executeUpdate를 통해 벌크 연산을 실행하게 되면 영속성 컨텍스트를 통하지 않고 바로 DB로 쿼리를 날린다.

3. 처음 member1,2,3은 현재 age값이 설정되어 있지 않기 때문에 0으로 초기화 된 상태에서 영속성 컨텍스트에 저장되어 있는 상태다.

4. 벌크 연산을 통해 DB에 UPDATE 쿼리를 날리게 되면 DB에는

 set m.age = 20

를 통해 멤버 전체의 나이가 20살로 업데이트 되어 있는 상태지만 영속성 컨텍스트 즉, 메모리에는 0으로 현재 남아있는 상황이다.

- 즉, 데이터 정합성에 맞지 않는다.


1. clear() 안했을 때

            //2222222
            Member findMember = em.find(Member.class, member1.getId());
            System.out.println("findMember.getAge() = " + findMember.getAge());

- 영속성 컨텍스트를 비우지 않으면 member1,2,3 age의 값이 0으로 저장되어 있기 때문에 find를 해도 DB에서 변경된 값을 불러오는 것이 아닌 영속성 컨텍스트에 저장된 0의 값을 가져오게 된다.

 

2. clear() 했을 때

//3333333
            em.clear();

            //2222222
            Member findMember = em.find(Member.class, member1.getId());
            System.out.println("findMember.getAge() = " + findMember.getAge());

- clear()를 한 후 member의 age를 조회하게 되면 영속성 컨텍스트에 값이 없기 때문에 DB에서 새롭게 값을 영속성 컨텍스트에 가져와서 값을 조회한다.

- DB에서 새롭게 값을 가져왔기 때문에 벌크 연산에 의해 변경된 값이 정상적으로 출력되는 것을 확인 할 수 있다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

출처 : 인프런 - 김영한 (자바 ORM 표준 JPA 프로그래밍 - 기본편)

728x90

'Programming > JPA(KYH)' 카테고리의 다른 글

JPA - API (지연 로딩과 조회 성능 최적화) 기본  (0) 2023.07.21
JPA - API 개발 기본  (0) 2023.07.19
JPA - 엔티티 직접 사용  (0) 2023.07.19
JPA - 페치 조인 (2)  (0) 2023.07.19
JPA - 페치 조인 (1)  (0) 2023.07.19