엔티티의 상태를 자동으로 감지하여 변경된 내용을 데이터베이스에 반영하는 JPA 핵심 기능 중 하나 출처: 엔티티 매니저와 영속성 컨텍스트를 정확하게 이해해보자
(https://psvm.kr/posts/tutorials/jpa/3-em-and-persistence-context) 영속성 컨텍스트는 EntityManager가 관리하는 캐시 영역으로, 영속성 엔티티 인스턴스들의 모음이다. 엔티티의 생명주기를 담당하고, 엔티티의 CRUD와 불러온 엔티티를 기억하는 1차 캐시 역할을 한다. 영속성 컨텍스트 안의 엔티티는 JPA가 지속적으로 상태 변화를 감지한다.
트랜잭션이 시작된 후, 영속성 컨텍스트에는 엔티티가 저장된다. 이때, JPA는 해당 엔티티의 스냅샷을 저장한다. 이후 엔티티 객체의 필드 값이 변경되면, JPA는 스냅샷과 현재 상태를 비교하여 변경 사항을 감지한다. 이러한 과정을 JPA의 더티 체킹(Dirty checking, 변경 감지)이라고 부른다.
트랜잭션이 커밋될 때, 변경된 엔티티를 확인하고 변경된 필드에 대해서만 UPDATE 쿼리를 자동으로 생성하여 DB에 반영한다. 개발자가 save() 같은 메서드를 호출하지 않아도 변경 사항이 자동으로 적용되는 것이다.
더티 체킹이 시작되는 시점
1. 트랜잭션이 커밋되기 직전 - 기본적으로 트랜잭션 커밋 시점에 발생 - JPA가 flush()를 호출해서 변경사항을 DB에 동기화하기 때문 - 영속성 컨텍스트가 동작할 때 더티 체킹이 시작된다.(스냅샷 저장 - 엔티티 변경 시 변경된 필드를 스냅샷과 비교) - flush는 DB와 영속성 컨텍스트 간의 동기화를 수행하는 단계로, 이 과정에서 더티 체킹이 수행되고 업데이트된다.
2. 명시적 flush() 호출 시 - EntityManager.flush() 호출 시 - 트랜잭션 커밋과 무관하게 엔티티 상태를 DB에 반영하도록 강제하는 경우에 해당한다.
@DynamicUpdate
JPA 엔티티에 적용할 수 있는 클래스 수준의 어노테이션 JPA가 아닌 하이버네이트의 기능으로, 엔티티에 추가하면 변경점 업데이트 시 변경된 필드만 update되게 쿼리를 쓰도록 하는 기능
이 어노테이션을 달지 않으면, 기본적으로 JPA 엔티티가 변경될 시 전체 칼럼을 대상으로 변경쿼리가 작성된다.예를 들어 age만 변경되는 상황에서도, name(변경 x)과 age(변경 o) 모두가 업데이트 쿼리에 포함되어 쿼리문이 나온다. 이는 업데이트를 위해 이미 캐싱된 SQL 구문을 사용하기 때문으로, @DynamicUpdate 어노테이션을 엔티티에 적용하면 이 기본 캐싱 구문을 사용하는 게 아니라, 엔티티를 업데이트할 때마다 (변경된 컬럼만을 포함하는) SQL 구문을 새로 만들게 된다.
주로 많은 수의 칼럼이 있고 특정 몇 개 칼럼만 자주 변경될 때 사용된다.
@DynamicInsert
위와 같은 역할을 하는 어노테이션으로, 엔티티에 적용하게 되면 Insert 쿼리를 날릴 때 null값은 제외됨. () 칼럼이 많아진다면 처리에 걸리는 시간이 줄어들 수 있다.