JPA를 사용할 때 엄청 큰 장점으로 뽑히는 더티 체킹에 대해서 알아보는 시간을 가졌다.
이해는 가지만 당장 실제로 프로젝트에 활용하는데는 시간이 조금 더 걸릴 듯하다.
이번 미니 프로젝트에 녹여낼 수 있다면 도전해보는걸로 생각하고있다.
여기에서 Dirty란 상태의 변화가 생긴 정도로 이해하시면 됩니다.
즉, Dirty Checking이란 상태 변경 검사 입니다.
JPA에서는 트랜잭션이 끝나는 시점에 변화가 있는 모든 엔티티 객체를 데이터베이스에 자동으로 반영해줍니다.
이때 변화가 있다의 기준은 최초 조회 상태입니다.
JPA에서는 엔티티를 조회하면 해당 엔티티의 조회 상태 그대로 스냅샷을 만들어놓습니다.
그리고 트랜잭션이 끝나는 시점에는 이 스냅샷과 비교해서 다른점이 있다면 Update Query를 데이터베이스로 전달합니다.
당연히 이런 상태 변경 검사의 대상은 영속성 컨텍스트가 관리하는 엔티티에만 적용 됩니다.
등 준영속/비영속 상태의 엔티티는 Dirty Checking 대상에 포함되지 않습니다.
즉, 값을 변경해도 데이터베이스에 반영되지 않는다는 것이죠.
@RequiredArgsConstructor
@Service
public class PayService {
public void updateNative(Long id, String tradeNo) {
EntityManager em = entityManagerFactory.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin(); //트랜잭션 시작
Pay pay = em.find(Pay.class, id);
pay.changeTradeNo(tradeNo); // 엔티티만 변경
tx.commit(); //트랜잭션 커밋
}
}
코드를 보시면 별도로 데이터베이스에 save 하지 않습니다.
여기서 save 메소드로 변경 사항을 저장하지 않았음에도 update 쿼리가 실행된다.
@Transactional
@RequiredArgsConstructor
@Service
public class PayService {
private final PayRepository payRepository;
@Transactional
public void update(Long id, String tradeNo) {
Pay pay = payRepository.getOne(id);
pay.changeTradeNo(tradeNo);
}
}
Dirty Checking으로 생성되는 update 쿼리는 기본적으로 모든 필드를 업데이트합니다.
JPA에서는 전체 필드를 업데이트하는 방식을 기본값으로 사용합니다.
전체 필드를 업데이트하는 방식의 장점은 다음과 같습니다.
다만, 필드가 20~30개 이상인 경우엔 이런 전체 필드 Update 쿼리가 부담스러울 수 있습니다.
사실 이런 경우 정규화가 잘못된 경우일 확률이 높습니다.
한 테이블에 필드 30개는 확실히 많습니다.
현재 운영중인 정산 서비스에는 데이터양이나 복잡도가 국내에서 손꼽히지만 15개 넘는 필드를 가진 테이블은 없습니다.
그래서 이런 경우엔 @DynamicUpdate
로 변경 필드만 반영되도록 할 수 있습니다.
엔티티 최상단에 아래와 같이 @DynamicUpdate
를 선언해주시면 됩니다.
@Getter
@NoArgsConstructor
@Entity
@DynamicUpdate // 변경한 필드만 대응
public class Pay {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String tradeNo;
private long amount;