JPA Dirty Check
엔티티 객체의 필드 값이 트랜잭션 안에서 변경되었을 때, 명시적으로 save() 하지 않아도 JPA가 자동으로 UPDATE SQL을 수행함.
update 메서드를 직접 호출하지 않아도 됨. (save() 필요 없음)
트랜잭션 안에서 객체 상태만 변경하면 JPA가 자동 감지하여 SQL을 생성
비즈니스 로직에서 엔티티 중심 설계 가능
public OrderResponse createOrder(OrderCreateRequest request, LocalDateTime registered) {
List<String> productNumbers = request.getProductNumbers();
List<Product> products = findProductsBy(productNumbers);
// 재고 차감 체크가 필요한 상품들 filter
List<String> stockProductNumbers = products.stream()
.filter(product -> ProductType.containStockType(product.getType()))
.map(Product::getProductNumber)
.collect(Collectors.toList());
// 재고 엔티티 조회
List<Stock> stocks = stockRepository.findAllByProductNumberIn(stockProductNumbers);
Map<String, Stock> stockMap = stocks.stream()
.collect(Collectors.toMap(Stock::getProductNumber, s -> s));
// 상품별 couting
Map<String, Long> productCountingMap = stockProductNumbers.stream()
.collect(Collectors.groupingBy(p -> p, Collectors.counting()));
// 재고 차감 시도
for(Stock stock : stockMap.values()) {
int quantity = productCountingMap.get(stock.getProductNumber()).intValue();
if(stock.isQuantityLessThan(quantity)){
throw new IllegalArgumentException("재고가 부족한 상품이 있습니다.");
}
stock.deductQuantity(quantity);
// stockRepository.save(stock);
}
Order order = Order.create(products,registered);
Order savedOrder = orderRepository.save(order);
// 저장이 된 후에야 Order에 id값 부여됨
return OrderResponse.of(savedOrder);
}
JPA에서 최초에 조회해올 때 스냅샷을 찍고, 마지막 Transaction 종료 시점에 인스턴스를 비교 후 달라진 부분이 있다면 update 쿼리 발생.
🔸 변경 감지가 동작하는 조건
조건
설명
영속 상태
EntityManager
가 관리하는 객체여야 함 (find()
, save()
등으로 불러온 것)
트랜잭션 범위 안
@Transactional
로 트랜잭션이 시작되어 있어야 함
필드 변경
엔티티 객체의 필드 값을 setter나 메서드로 변경해야 함
flush 시점
트랜잭션 커밋 시점 또는 flush()
호출 시점에 변경 감지 실행
🔸 Dirty Checking과 merge()
의 차이
merge()
의 차이항목
Dirty Checking
merge()
대상
영속 상태의 엔티티
비영속 상태의 엔티티
방식
객체 필드 변경 자동 감지
객체의 모든 값 복사 (값이 null이어도 덮어씀)
용도
트랜잭션 내 값만 변경하고 싶을 때
외부 DTO 값을 업데이트할 때
// Dirty Checking (추천 방식)
order.setStatus(OrderStatus.COMPLETED);
// merge (주의: null 필드도 덮어씀)
em.merge(orderDto.toEntity());
🔸 변경 감지가 적용되지 않는 경우
트랜잭션 밖에서 변경
new
로 만든 객체 (영속 아님)영속성 컨텍스트에서 분리된 상태 (
detach
,clear
,close
등)
Last updated