본문 바로가기

JPA/JPQL

Bulk 연산

 

 

한 번에 많은 행을 삭제하거나 수정하는 연산을 Bulk 연산이라고 한다.
이번 글에서는 Bulk 연산을 하는 법과 주의점에 대해서 살펴보겠다.

 

Bulk 연산하기

String query = "update Student s set s.age = s.age + 1";
int updatedDataSize = em.createQuery(query).executeUpdate();
System.out.println("updatedDataSize = " + updatedDataSize);
로그
Hibernate: update Student set age=age+1
updatedDataSize = 3

executeUpdate()를 통해 delete나 update 쿼리를 날릴 수 있다.

또한 executeUpdate()는 쿼리를 통해 수정되거나 삭제된 행의 개수를 반환해준다.

 

 

이러한 Bulk 연산은 영속성 컨텍스트와는 무관하다.

다음 코드를 살펴보자!

String query = "update Student s set s.age = 0";
int updatedDataSize = em.createQuery(query).executeUpdate();
System.out.println("student = " + student.getAge());

System.out.println("student = " + student);
System.out.println("updatedDataSize = " + updatedDataSize);
로그
Hibernate: /* update Student s set s.age = 0 */
update Student set age=0
student = 21
student = Student(id=3, name=code-mania, age=21, club=Club(id=1, name=c1))
updatedDataSize = 3

결과를 보면 age를 0으로 update 했음에도,

기존에 있던 student의 age는 수정되지 않고 21로 되어있는 것을 확인할 수 있다.
즉, Bulk 연산은 영속성컨텍스트와는 무관한 것이다.

 

이를 해결하기 위해  다음 두 가지 방법 중 하나를 사용하면 된다.

 

1. Bulk 연산을 가장 먼저 실행한다.

DB로부터 데이터를 조회하는 등의 영속성 컨텍스트와 관련된 어떤 작업보다
Bulk 연산을 제일 먼저 실행하는 것이다.

이것이 불가능한 경우 2번 방법을 통해 해결한다.

 

2. 벌크 연산 수행 후 영속성 컨텍스트 초기화

벌크 연산을 수행 후 영속성 컨텍스트를 초기화해준다.
지금같은 경우 다음과 같이 코드를 작성하면 된다.

String query = "update Student s set s.age = 0";
int updatedDataSize = em.createQuery(query).executeUpdate();

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

Student findStudent = em.find(Student.class, student.getId());
System.out.println("findStudent = " + findStudent);
System.out.println("student = " + student);
System.out.println("updatedDataSize = " + updatedDataSize);
로그
Hibernate: update Student set age=0
Hibernate: select s.* where s.MEMBER_ID=?
Hibernate: select c.* from Club c where c.id=?
findStudent = Student(id=3, name=code-mania, age=0, club=Club(id=1, name=c1))
student = Student(id=3, name=code-mania, age=21, club=Club(id=1, name=c1))
updatedDataSize = 3

코드를 보면 Bulk 연산을 실행 후 영속성컨텍스트를 초기화하고 있다.

이렇게 초기화해도 기존에 있던 student가 없어지거나 수정되는 게 아니라
그저 준영속 상태가 되는 것뿐이다.
따라서 기존에 있던 student의 id를 이용해서 다시 student를 조회하고 있다.

그렇게 다시 조회한 findStudent의 age는 정상적으로 0으로 가져와진 것을 확인할 수 있다.

참고강의: 배달의 민족 개발팀장 김영한 강사님의 JPA 강의

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

JPQL 엔티티 조회  (0) 2021.10.15
페치조인 특징과 한계  (0) 2021.10.12
N+1과 fetch join  (0) 2021.10.02
경로표현식  (0) 2021.10.02
JPQL 함수  (0) 2021.09.25