본문 바로가기
Spring

[Spring] JPA 더티 체킹 (Dirty Checking)

by 가드 2022. 11. 25.
728x90

Querydsl 벌크 업데이트 대해서 글을 정리하려고 했는데 더티 체킹에 대한 내용이 있어서 먼저 더티 체킹에 대해 글을 써보려 한다.

JPA 더티 체킹(Dirty Checking)

Transaction안에서 Entity의 변경 상태를 확인하는 과정을 말한다. 즉, Entity의 상태 변경 검사를 뜻한다.

Transaction은 두 가지 방식을 사용한다.

1. Class 또는 Method에 @Transactional Annotation을 사용하는 방식
@Transactional
public void updateUser(Long id, String name) {
	Player player = playerRepository.findById(id);
	player.setName(name);
}

2. EntityTransaction을 이용하여 범위를 지정하는 방식
public void updateUser(Long id, String name) {
	EntityManager em = entityManagerFactory.createEntityManager(); 
	EntityTransaction tx = em.getTransaction();
	tx.begin(); //트랜잭션 시작
	Player player = em.find(Player.class, id);
	player.setName(name); // 엔티티 변경
	tx.commit(); //트랜잭션 커밋
}

설명 편의를 위해 2번 방식으로 설명을 해보자.

1. 트랜잭션 시작

2. Player Entity 조회

3. Player Entity의 Name 변경

4. 트랜잭션 커밋

Update 관련 쿼리 코드가 없다.

로그를 보니 당연하게 Player를 조회하는 select 쿼리는 발생되었고 그 이후 Update 쿼리가 발생되었다.

이유는 더티 체킹(Dirty Checking) 때문이다. 조회된 Player Entity 객체는 영속화되었고 트랜잭션이 끝나는 시점에 Entity 객체에 변환가 있는지 체크 후 변화가 있는 Entity를 데이터베이스에 자동으로 반영해주기 때문이다.

변화의 기준은 최초 조회 상태를 말한다.

즉, JPA에서는 Entity 조회가 발생하면 해당 객체를 스냅샷을 만들어 캐싱해 놓는다 (흔히 말하는 1차 캐시) 그리고 트랜잭션이 끝나는 시점에 캐싱한 스냅샷 객체와 비교해서 변경 건이 있다고 판단되면 Update Query가 발생하게 된다. 그래서 영속성 컨텍스트가 관리되는 Entity만 해당이 되며 준영속 또는 비영속 상태의 Entity는 더티 체킹 대상에 포함되지 않는다.

 

어? 그런데 잠시만... 난 name만 변경했는데 update 쿼리 로그를 보니 game, rank 등 변경되지 않는 컬럼들도 같이 업데이트 되었네..

더티 체킹으로 생성되는 Update Query는 기본적으로 모든 필드를 업데이트한다.

그래서 변경 컬럼만 업데이트를 하고 싶을 때는 @DynamicUpdate Annotation을 사용해서 변경 필드만 반영되도록 할 수 있다.

@Entity
@DynamicUpdate // <--- 선언
public class Player {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String game;
    private String name;
    private Integer rank;
}

다시 코드를 실행하면 로그에 name만 반영되는 것을 확인할 수 있다.

300x250

댓글