[JPA] 더티체킹(Dirty Checking)

윤재열·2022년 9월 30일
0

JPA

목록 보기
20/21
post-custom-banner

Spring Data Jpa 같은 ORM 구현체를 사용하다보면 더티체킹 이라는 단어를 종종 듣게 됩니다.

Example

  • PayService 클래스
@Log4j2
@RequiredArgsArgsConstructor
@Service
public class PayService{
	
    public void updateNative(Long id, String tradeNo){
    
    	EntityManager em = entityManagerFactory.createEntityManager();
        EntityTransaction tx = em.getTransaction();
        tx.begin();	// 트랜잭션 시작(1)
        Pay pay = em.find(Pay.class,id);	// (2)
        pay.changeTradeNo(tradeNo);	// 엔티티만 변경(3)
        tx.commit();	// 트랜잭션 커밋(4)
        
  • 코드로 보면 별도로 데이터베이스에는 save 하지 않습니다.

    1. 트랜잭션이 시작합니다.
    2. 엔티티를 조회합니다.
    3. 엔티티의 값을 변경합니다.
    4. 트랜잭션을 커밋합니다.
  • 여기서 DB에 update 쿼리에 관한 코드는 어디에도 없습니다.

  • 이 코드가 어떻게 작동하는지 테스트 코드

@SpringBootTest
public class PayServiceTest {

    @Autowired
    PayRepository payRepository;

    @Autowired
    PayService payService;

    @After
    public void tearDown() throws Exception {
        payRepository.deleteAll();
    }

    @Test
    public void entityManagerTest() {
        //given
        Pay pay = payRepository.save(new Pay("test1",  100));

        //when
        String updateTradeNo = "test2";
        payService.updateNative(pay.getId(), updateTradeNo);

        //then
        Pay saved = payRepository.findAll().get(0);
        assertThat(saved.getTradeNo()).isEqualTo(updateTradeNo);
    }
}
  • 테스트를 수행하면 아래와 같이 save 메서드로 변경사항을 저장하지 않았음에도 update 쿼리가 나갑니다.

  • 이에 대한 이유는 바로 Dirty Checking 때문입니다.

    • 여기서 Dirty 란 상태의 변화가 생긴 정도라고 이해하면 됩니다.
    • 즉 Dirty Checking 이란 상태 변경검사 입니다.
  • JPA 에서는 트랜잭션이 끝나는 시점에 변화가 있는 모든 엔티티 객체를 데이터 베이스에 자동으로 반영해줍니다.

  • 이때 변화가 있다의 기준은 최초 조회 상태입니다!!

  • JPA에서는 엔티티를 조회하면 해당 엔티티의 조회 상태 그대로 스냅샷을 만들어 놓습니다.
    그리고 트랜잭션이 끝나는 시점에서 이 스냅샷과 비교하여 다른점이 있다면 UpdateQuery를 DB에 전달합니다.

  • 이런 상태 변경 검사의 대상은 영속성 컨테스트가 관리하는 엔티티에만 적용됩니다.

    • detach된 엔티티( 준영속)
    • DB에 반영도기 전 처음 생성된 엔티티(비영속)
    • 위와 같이 준영속/비영속 상태의 엔티티는 Dirty Checking 대상에 포함되지 않습니다.
  • 즉 값을 변경해도 DB에는 반영되지 않습니다.

변경 부분만 update 하고 싶을 때

  • Dirty Checking 으로 생성되는 update 쿼리는 기본적으로 모든 필드를 업데이트 합니다.
  • JPA에서는 전체필드를 업데이트하는 방식을 기본값으로 사용합니다.

전체 필드를 업데이트 하는 방식의 장점

  • 생성되는 쿼리가 같아 부트 실행시점에 미리 만들어서 재사용이 가능합니다.
  • 데이터베이스 입장에서 쿼리 재사용이 가능합니다.
    ( 동일한 쿼리를 받으면 이전에 파싱된 쿼리를 재사용합니다.)
  • 하지만 필드가 2~30 개가 이상인 경우에는 이런 전체필드가 update 쿼리가 부담스러울 수 있습니다.

  • 그래서 이런 경우에는 @DynamicUpdate로 변경 필드만 반영되도록 할 수 있습니다.

  • 아래와 같이 엔티티 최상단에 @DynamicUpdate만 선언해주면 됩니다.

@Getter
@NoArgsConstructor
@Entity
@DynamicUpdate // 변경한 필드만 대응
public class Pay {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String tradeNo;
    private long amount;
  • 그리고 다시 테스트를 진행하면 아래와 같이 변경된 필드(tradeNo)에만 update 쿼리가 나갑니다.
profile
블로그 이전합니다! https://jyyoun1022.tistory.com/
post-custom-banner

0개의 댓글