지난 포스팅에서 영속성컨텍스트의 이점에서 변경감지(DirtyChecking)를 다루어보았다.
엔티티에 변경사항이 감지되면 영속성컨텍스트는 자동으로 UPDATE,DELETE문을 생성하였다. 그러나 이 방법은 변경감지 한 건당 하나의 쿼리문을 생성한다. 만약 100개의 변경감지가 만들어졌다면 100개의 쿼리가 생성되어 실행된다. 이는 성능에 좋지 못하다. 그래서 UPDATE문,DELETE문을 JPQL로 만들어 여러 건의 변경및삭제를 가능하게 만들었는데, 이를 벌크연산이라 부른다.
//UPDATE문
String jpql = "UPDATE Person p SET p.name = :newName WHERE p.id = :personId";
int updatedCount = entityManager.createQuery(jpql)
.setParameter("newName", newName)
.setParameter("personId", personId)
.executeUpdate();
//DELETE문
String jpql = "DELETE FROM Person p WHERE p.age = :age";
int deletedCount = entityManager.createQuery(jpql)
.setParameter("age", age)
.executeUpdate();
이로써 여러 건의 변경사항에 대응할 수 있게 되었다. 그러나 한 가지 주의점이 있다.
JPQL은 파싱된 후, 영속성 컨텍스트를 거치지 않는다. 바로 데이터베이스에 실행된다.
엔티티매니저의 find메소드로 영속성컨텍스트에 Person엔티티 하나를 DB에서 조회했다고 가정해보자. 영속성 컨텍스트에 조회된 Person의 나이는 50이다.
JPQL은 영속성컨텍스트를 거치지 않고 DB에 실행되므로 DB의 나이만 30으로 UPDATE된다. 영속성컨텍스트의 나이는 그대로 50이다. 여기서 데이터 정합성의 문제가 발생한다. 영속성컨텍스트를 초기화하지 않고 find메소드로 조회한다면 30이 아닌 50을 가져온다. 이처럼 벌크연산은 정합성을 깨뜨리는 문제를 발생시킬 수 있다.
위 문제는 두 가지 방법으로 해결할 수 있다.
첫번째 방법 : 벌크연산부터 수행한다.
find 같은 영속성컨텍스트를 거치는 작업보다 벌크연산을 먼저 수행하는 방식으로 코드를 진행한다.
두번째 방법 : 벌크연산 수행 후 영속성컨텍스트를 초기화한다.
벌크연산이 수행되면 영속성컨텍스트의 내부데이터는 정합성이 깨져있다. entitymanger.clear()로 영속성컨텍스트를 초기화하여 정합성이 깨진 데이터를 조회하는 불상사를 차단한다.
참고자료
'JPA > JPQL' 카테고리의 다른 글
[JPA] Named 쿼리 (0) | 2023.06.19 |
---|---|
[JPA] 상속관계에서 JPQL ( TYPE, TREAT ) (0) | 2023.06.16 |
[JPA] 페치 조인 ( JOIN FETCH ) (0) | 2023.06.15 |
[JPA] 묵시적 조인보다는 명시적 조인 (0) | 2023.06.15 |
[JPA] 쿼리결과 변환하기 ( JPQL 함수 ) (0) | 2023.06.14 |