1. 서론
- 프로젝트에서 JPA를 사용하여 CRUD 중 Update를 구현할 때,보통 변경감지(Dirty Checking)를 이용합니다.
- Entity를 조회하여 조회된 Entity 데이터를 변경만 하면 데이터 베이스에 자동으로 반영이 되도록 하는 기능입니다.
1 - 1. 영속성 컨텍스트
- JPA에서는 Entity Manager를 통해 데이터 베이스 작업을 처리합니다.
- Entity Manager는 내부적으로 영속성 컨텍스트라는 메모리 영역을 가지며 이 안에 데이터베이스로부터 조회한 Entity 객체들이 저장되어 있습니다.
1 - 2. 영속성 컨텍스트 변경감지(더티 체킹)
- JPA는 트랜잭션 되는 순간 내부적으로 flush()가 호출됩니다.
- 그때 엔티티와 1차 캐시 내의 스냅샷(최초 상태)을 비교합니다.
- 비교했을 때, 변경이 있으면 Update SQL을 쓰기 지연 SQL 저장소에 저장하고,
- 커밋이 되면 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으로 요청이 들어온 경우 더티체킹으로 손쉽게 할 수 있지만,
한 번에 많은 데이터를 변경해야할 때는 벌크 업데이트로 처리해야할 것이다.
근데 아직 일일 숙제 초기화 로직이 남아있네...
얘는 휴식게이지 계산도 해야되서 더 복잡...