728x90

✅ Write-Behind (쓰기 지연) 란?

JPA의 핵심 기능 중 하나로, 엔티티 객체의 변경을 바로 DB에 반영하지 않고 트랜잭션이 커밋될 때 한 번에 반영하는 전략이야.

 


💡 왜 쓰기 지연을 사용할까?

  1. 성능 최적화
    → 객체를 여러 번 수정할 때마다 DB에 SQL을 날리면 성능이 떨어져.
    → JPA는 SQL을 "모아서 한 번에" 보냄으로써 성능을 높여줘.
  2. 트랜잭션 관리 효율
    → 트랜잭션 도중 예외가 발생하면, 실제 DB에는 반영되지 않았기 때문에 롤백이 쉬움.

 


💡 예시로 이해해보자

@Transactional
public void updateUser() {
    User user = em.find(User.class, 1L);
    user.setName("홍길동");
    user.setEmail("gildong@example.com");

    // 아직 DB에는 아무 일도 일어나지 않음!
    // 변경 사항은 영속성 컨텍스트 안에만 존재

    // 여기서 트랜잭션이 커밋되면 → 한 번에 UPDATE SQL 2개가 나감!
}

📌 무슨 일이 벌어졌을까?

  1. find()로 가져온 user는 영속성 컨텍스트에 등록됨.
  2. setName(), setEmail()로 데이터를 변경함.
  3. 이때 JPA는 바로 SQL을 실행하지 않음.
  4. commit() 시점에 변경된 필드를 감지하여 SQL을 생성함.
    • UPDATE user SET name='홍길동' WHERE id=1
    • UPDATE user SET email='gildong@example.com' WHERE id=1

✔️ 이것이 쓰기 지연(Write-Behind) 이고,
변경 감지(Dirty Checking)와 함께 작동해.

 


🔁 함께 기억할 개념

개념 설명
Dirty Checking 엔티티 객체의 상태가 변경됐는지 감지함
1차 캐시 트랜잭션 동안 EntityManager 내부에 객체를 저장하는 캐시
Write-Behind 변경된 데이터를 DB에 바로 쓰지 않고 커밋 시점에 반영함

 


🎯 언제 flush가 일어날까?

JPA는 다음과 같은 시점에 쓰기 지연된 SQL을 DB에 보내:

  • 트랜잭션 커밋 시점
  • JPQL / Native Query 실행 전
  • flush() 명시적 호출 시

 


🚨 단점은 없을까?

  • 커밋 시점까지 DB에 반영되지 않으므로, 중간에 DB에 반영된 결과를 확인할 수 없음.
  • 중간 SQL 실행 순서가 중요한 로직에는 flush()를 수동으로 호출해야 함.

 


흐름도

728x90