상태 변경 감지 대상은 영속성 컨텍스트가 관리하는 엔티티에만 적용된다.
이러한 데이터는 dirty checking 대상이 아니고 엔티티(값)이 update 되지 않는다.
JPA의 기본전략으로 생성되는 수정쿼리는 엔티티의 모든 필드를 업데이트 --> 권장
전체 필드를 업데이트하는 방식(정적 수정 쿼리)의 장점? 수정 쿼리가 항상 같다
동적 수정 쿼리를 사용하려면? @DynamicUpdate
어노테이션을 활용한다.
@DynamicInsert
: null이 아닌 데이터(필드)에 대해서만 insert query를 생성하는 어노테이션
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
public class DirtyCheckingAndMerge {
public static void main(String[] args) {
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("hello");
EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
try {
Member member = new Member();
member.setName("ron2");
member.setCity("seoul");
member.setStreet("gonghangdaero");
member.setZipcode("111-111");
entityManager.persist(member); // member 생성
member.setName("updatedRon2"); // update
entityManager.flush(); // (1) member insert, (2) update (dirty checking)
entityManager.clear();
Member findMember = entityManager.find(Member.class, 1L); // (3) select
entityManager.clear(); // 준영속 병합을 위해서 clear
System.out.println("findmember 영속? " + entityManager.contains(findMember));
// false -> 준영속
findMember.setName("mergedRon2"); // 이름 변경
Member mergedMember = entityManager.merge(findMember);
// 병합(데이터 밀어넣기) (4) 영속성 컨텍스트에 해당 member 있는지 조회 -> 없어서 DB에서 조회
System.out.println("mergedMemer 영속? " + entityManager.contains(mergedMember)); // true
transaction.commit(); // (5) update 쿼리 (내부적으로 flush()시점)
} catch (Exception e) {
transaction.rollback();
} finally {
entityManager.close();
}
entityManagerFactory.close();
}
}
-- (1) member 생성
Hibernate:
/* insert jpashop.Member
*/ insert
into
MEMBER
(MEMBER_ID, city, name, street, zipcode)
values
(default, ?, ?, ?, ?)
-- (2) update (dirty checking)
Hibernate:
/* update
jpashop.Member */ update
MEMBER
set
city=?,
name=?,
street=?,
zipcode=?
where
MEMBER_ID=?
-- (3) select
Hibernate:
select
member0_.MEMBER_ID as member_i1_1_0_,
member0_.city as city2_1_0_,
member0_.name as name3_1_0_,
member0_.street as street4_1_0_,
member0_.zipcode as zipcode5_1_0_
from
MEMBER member0_
where
member0_.MEMBER_ID=?
-- findmember 영속? false
-- (4) 영속성 컨텍스트에 해당 member 있는지 조회
Hibernate:
/* load jpashop.Member */ select
member0_.MEMBER_ID as member_i1_1_0_,
member0_.city as city2_1_0_,
member0_.name as name3_1_0_,
member0_.street as street4_1_0_,
member0_.zipcode as zipcode5_1_0_
from
MEMBER member0_
where
member0_.MEMBER_ID=?
-- mergedMemer 영속? true
-- (5) update 쿼리
Hibernate:
/* update
jpashop.Member */ update
MEMBER
set
city=?,
name=?,
street=?,
zipcode=?
where
MEMBER_ID=?
@DynamicUpdate
어노테이션을 붙이면, merge를 통한 업데이트 또한 동적 쿼리로 생성된다.