[JPA] 더티 체킹(Dirty Checking)

off_sujin·2021년 9월 1일
0
@Transactional
    public Long update(Long id, PostsUpdateRequestDto requestDto) {
        Posts posts = postsRepository.findById(id)
                                    .orElseThrow(() -> new IllegalArgumentException("해당 게시글이 없습니다. id = " + id));

        posts.update(requestDto.getTitle(), requestDto.getContent());

        return id;
    }

위의 코드를 보면 데이터베이스에 Update 쿼리를 날리지 않고 Entity 객체의 값만 변경하는 것을 볼 수 있습니다.
이것이 가능한 이유는 더티 체킹(Dirty Checking) 덕분입니다.


더티 체킹(Dirty Checking)

더티 체킹이란 엔티티의 변경사항을 DB에 자동반영하는 것입니다.

JPA는 엔티티를 영속성 컨텍스트에 보관할 때, 최초 조회 상태 그대로 스냅샷을 남겨놓습니다.
그리고 flush 시점에 스냅샷과 비교하여 변경된 엔티티를 찾아 변경사항을 데이터베이스에 전달합니다.

public Long update(Long id, PostsUpdaterequestDto requestDto) {
        EntityManager em = em.createEntityManager();	//엔티티 매니저 생성
        EntityTransaction transaction = em.getTransaction();	//트랜잭션 시작

        transaction.begin();	//트랜잭션 시작

        Posts posts = em.find(Posts.class, id);
        posts.update(requestDto.getTitle(), requestDto.getContent());	//영속 엔티티 데이터 수정

        transaction.commit();	//트랜잭션 커밋
        
        return id;
    }

위의 예제코드를 네이티브한 코드로 변경한 것입니다.
더티 체킹의 작동과정은 다음과 같습니다.

  1. 트랜잭션을 commit하면 flush()를 호출합니다.
  2. 영속성 컨텍스트에 있는 모든 엔티티를 스냅샷과 비교합니다.
  3. 수정된 엔티티가 있으면 UPDATE SQL을 생성하고 쓰기지연 SQL 저장소에 보관합니다.
  4. 쓰기지연 SQL을 데이터베이스에 전송합니다.
  5. 데이터베이스 트랜잭션을 commit합니다.

더티체킹은 트랜잭션 안에서 엔티티가 변경되어야하며, 영속성 컨텍스트가 관리하는 영속상태(Managed)의 엔티티에 대해서만 적용됩니다.

따라서 데이터베이스에 저장하지 않은 엔티티 객체(비영속)나 detach, clear, close된 엔티티(준영속)는 값을 변경해도 데이터베이스에 반영되지 않습니다.


더티 체킹으로 생성되는 UPDATE SQL은 엔티티의 모든 필드를 업데이트합니다.
모든 필드를 DB에 보내면 데이터 전송량이 증가하지만 수정 쿼리가 항상 같기 때문에 미리 생성하고 재사용이 가능하게 됩니다. 또한 DB 입장에서 동일한 쿼리를 받으면 이전에 파싱된 쿼리를 재사용할 수 있다는 장점이 있습니다.

만약 원하는 필드만 업데이트하고 싶다면 엔티티를 정의할 떄 @DynamicUpdate 어노테이션을 추가하면 됩니다.

profile
학습 중..

0개의 댓글