Project/LOATODO

[LOATODO] JPA 영속성 컨텍스트 더티체킹 VS JPQL로 벌크업데이트

마볼링 2023. 11. 8. 18:48

1. 서론

  • 프로젝트에서 JPA를 사용하여 CRUD 중 Update를 구현할 때,보통 변경감지(Dirty Checking)를 이용합니다.
  • Entity를 조회하여 조회된 Entity 데이터를 변경만 하면 데이터 베이스에 자동으로 반영이 되도록 하는 기능입니다.

 

1 - 1. 영속성 컨텍스트

  • JPA에서는 Entity Manager를 통해 데이터 베이스 작업을 처리합니다.
  • Entity Manager는 내부적으로 영속성 컨텍스트라는 메모리 영역을 가지며 이 안에 데이터베이스로부터 조회한 Entity 객체들이 저장되어 있습니다.

 

1 - 2. 영속성 컨텍스트 변경감지(더티 체킹)

 

  1. JPA는 트랜잭션 되는 순간 내부적으로 flush()가 호출됩니다.
  2. 그때 엔티티와 1차 캐시 내의 스냅샷(최초 상태)을 비교합니다.
  3. 비교했을 때, 변경이 있으면 Update SQL을 쓰기 지연 SQL 저장소에 저장하고,
  4. 커밋이 되면 flush()가 호출되서 DB에 Update 쿼리가 나갑니다.

 

1 - 3. 그럼 데이터가 10만개, 100만개 등 엄청 많을 때 더티 체킹하면?

 

뭘 어떻게 돼... 메모리 부족으로 터지지.....

매주 수요일 오전 6시에 LoaTodo 주간 숙제초기화를 진행하는데
주간 숙제 데이터가 많아져서 처리하는 과정에서 서버가 다운됬다...
그로인해 일일 숙제, 주간숙제 초기화가 둘 다 진행이 안되었다.

 

 

2. 개발

2 - 1. 기존 주간 숙제 초기화 로직

 

-> 데이터를 전부 읽어서 하나씩 더티체킹하는 방식

 

 

다수의 데이터를 영속성 컨텍스트에 올리기 때문에 메모리 부족현상이 발생합니다.

 

2 - 2. 변경된 주간 숙제 초기화 로직

  • 주간 레이드 초기화 관련 bulk 업데이트 쿼리
  • 2주 쿨타임 레이드 계산 후 checked를 변경합니다.

  • 주간 숙제 초기화 관련 bulk 업데이트 쿼리

 

3. 성능 비교

3 - 1. 기존 주간 숙제 초기화

-> 하나씩 update 쿼리 날리는 중

 

3 - 2. 변경된 주간 숙제 초기화

-> update 쿼리문 한 줄

 

3 - 3. 결과

  • 기존 : 평균 37초
  • 변경 : 평균 2.5초

-> 93.24% 성능향상

 

 

4. 정리 및 후기

JPA 관련하여 여러강의를 봤지만... 대다수 더티체킹을 이용하여 데이터를 변경하는 내용이다.

물론 일반적인 PutMapping으로 요청이 들어온 경우 더티체킹으로 손쉽게 할 수 있지만, 

한 번에 많은 데이터를 변경해야할 때는 벌크 업데이트로 처리해야할 것이다.

 

근데 아직 일일 숙제 초기화 로직이 남아있네...

얘는 휴식게이지 계산도 해야되서 더 복잡...