ScheduleApp develop 과제를 진행하다가,
SQL을 직접 썼을 때는 아래처럼 원하는 필드만 쿼리로 쉽게 처리했다.
UPDATE table SET deleted_at = NOW() WHERE id = ?
하지만 JPA는 처음이라서 어떻게 원하는 필드만 업데이트할 수 있을지 고민하게 됐다.
그 과정에서 Dirty Checking이라는 개념을 알게 되었고,
조금 어려웠기 때문에 이 내용을 정리해서 velog에 기록해본다.
JPA가 DB의 상태 변경을 자동으로 감지해서 필요한 SQL만 날려주는 기능!
@Transactional이 필수다!Dirty Checking을 이해하는 데 방해가 되었던 오해 두 가지:
@Transactional 안 써도 save(user)는 잘 되던데?findById()를 여러 번 호출해도 DB에 한 번만 요청되는데 그 이유는,@Transactional 없이 save(user)가 작동하는 이유는?JpaRepository나 CrudRepository의 메서드에 이미 @Transactional이 붙어있기 때문이다.1. 트랜잭션 시작 (@Transactional)
→ 영속성 컨텍스트 & EntityManager 생성
2. findById로 엔티티 조회
→ 조회한 객체 + Snapshot(초기 상태) 저장
→ 내부적으로는 Map<Field, Value> 형태
3. 엔티티 필드 변경
→ 객체는 변경되지만 아직 DB 반영 X
4. flush() 발생
→ 현재 객체 상태 vs 스냅샷 비교
→ 변경된 필드만 추려서 UPDATE SQL 생성
5. DB에 COMMIT → 변경 사항 최종 반영
💡 참고
save(user)를 사용할 때user객체에 ID가 없다면 JPA는 기존 데이터를 조회하지 않고 바로 INSERT를 실행함 → Dirty Checking 아님!
| 개념 | 설명 |
|---|---|
| Dirty Checking | 영속성 컨텍스트 내부에서 스냅샷과 변경된 엔티티를 비교해 변경된 필드만 UPDATE |
| 트랜잭션 | DB에 대한 하나의 논리적 작업 단위. 커밋 시 반영됨 |
| 영속성 컨텍스트 | 엔티티와 스냅샷을 저장하는 임시 저장소. Dirty Checking의 핵심 요소 |
이렇게 글로 정리하니 이제서야 머릿속에 개념이 좀 들어오는 것 같다 😌
처음엔 헷갈렸던 개념들도 정리하면서 자연스럽게 연결되었다.
JPA는 처음일수록 더티 체킹 개념을 꼭 짚고 넘어가는 것이 중요한 것 같다!