네로개발일기

개발자 네로의 개발 일기, 자바를 좋아합니다 !

반응형

Dirty Checking

Spring Data JPA와 같은 ORM 구현체를 사용하다보면 더티체킹을 만나볼 수 있다.

@Slf4j
@RequiredArgsConstructor
@Service
public class PayService {

    private final EntityManager em;

    public void updateNative(Long id, String tradeNo) {
        EntityTransaction tx = em.getTransaction();
        
        tx.begin();
        
        Pay pay = em.find(Pay.class, id);
        pay.changeTradeNo(tradeNo);
        
        tx.commit();
    }
}

save()를 하지 않는다.

1. 트랜잭션이 시작되고

2. 엔티티를 조회하고

3. 엔티티의 값을 변경하고 

4. 트랜잭션을 커밋한다.

 

update 쿼리는 없다.

 

@RunWith(SpringRunner.class)
@SpringBootTest
public class PayServiceTest {
    
    @Autowired
    PayRepository payRepsitory;
    
    @Autowired
    PayService payService;
    
    @After
    public void tearDown() throws Exception {
        payRepository.deleteAll();
    }
    
    @Test
    public void updateDirtyChecking() {
        // 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(save.getTradeNo()).isEqualTo(updateTradeNo);
    }
}

save() 메서드로 저장하지 않아도 dirty checking으로 update 쿼리가 실행되었다.

 

JPA에서는 트랜잭션이 끝나는 시점에 변화가 있는 모든 엔티티 객체를 데이터베이스에 자동으로 반영해준다.

상태 변경 검사의 대상은 영속성 컨텍스트가 관리하는 엔티티에만 적용된다.

 

detach된 엔티티(준영속), DB에 반영되기 전 처음 생성된 엔티티(비영속) 상태의 엔티티는 Dirty Checking 대상이 아니다.

 

변경 부분만 update 하고 싶을 때는

Dirty Checking으로 생성되는 update 쿼리는 기본적으로 모든 필드를 업데이트한다.

 

JPA는 전체 필드를 업데이트하는 방식을 기본값으로 사용한다.

전체 필드를 업데이트하는 방식의 장점은 다음과 같다.

- 생성되는 쿼리가 같아 부트 실행시점에 미리 만들어서 재사용이 가능하다.

- 데이터베이스 입장에서 쿼리 재사용이 가능하다. (동일한 쿼리를 받으면 이전에 파싱된 쿼리를 재사용한다.)

 

필드가 20~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;
}
728x90
반응형
blog image

Written by ner.o

개발자 네로의 개발 일기, 자바를 좋아합니다 !