TIL - 26.01.06

이준연·2026년 1월 6일

학습 키워드


  • JPA 영속성 컨텍스트

JPA 영속성 컨텍스트


영속성 컨텍스트란
영속성 컨텍스트는 단어 그대로 엔티티(Entity)를 영속적으로 저장하는 환경이라는 뜻입니다. 하지만 JPA에서는 엔티티의 생명주기를 관리하고, 애플리케이션과 데이터베이스 사이에서 수많은 최적화 작업을 해주는 논리적인 공간(메모리 공간)이라고 이해해야 합니다.
마치 효율적인 작업을 위해 필요한 도구와 재료들을 미리 꺼내놓는 '작업대'와 같습니다. JPA는 이 작업대 위에서 엔티티들을 관리하다가, 작업이 끝나면(트랜잭션이 끝나면) 최종 결과물만 DB에 반영합니다.

💡 트렌젝션: 여러 작업을 하나의 단위로 묶어서 모두 성공하거나 모두 실팰하게 하는 것.

영속성 컨텍스트 사용 이유

1. 1차캐시와 동일성(Identity) 보장

  • 1차 캐시:
    영속성 컨텍스트는 일종의 Map 형태의 캐시 저장소를 갖고 있습니다.
    • 엔티티가 영속성 컨텍스트의 1차 캐시에 저장됩니다.
    • 먼저 1차 캐시를 확인합니다. 캐시에 동일한 ID의 엔티티 객체가 있으면, DB를 조회하지 않고 캐시의 엔티티를 즉시 반환합니다.
  • 동일성 보장:
    1차 캐시 덕분에, 같은 트랜잭션 안에서 같은 ID로 조회한 엔티티는 항상 동일한 메모리 주소의 인스턴스(== 비교 시 true)임이 보장됩니다.
// 같은 트랜잭션 내에서
// Member를 저장
Member savedMember = memberRepository.save(newMember);
// ...
// 위에서 저장한 Member의 id로 Member를 조회
Member member = memberRepository.findById(dto.getId()).orElseThrow(
() -> new IllegalStateExcetion("존재하지 않는 멤버입니다.")
)
// 여기서 savedMember는 영속성 컨텍스트에 저장되고,
// 그 이후에 동일한 엔티티를 조회하면 DB를 조회하지 않고 캐시의 엔티티를 반환합니

2. 변경 감지(Dirty Checking)

  • 동작원리:
    1. 트랜잭션이 커밋되기 직전, 영속성 컨텍스트는 1차 캐시에 있는 모든 엔티티의 최초상태(스냅샷)와 현재 상태를 비교합니다.
    2. 만약 두 상태가 다르다면(즉, 엔티티의 필드 값이 변경되었다면), JPA는 변경된 내용을 감지하고 자동으로 UPDATE SQL을 생성하여 DB에 반영합니다.
    3. 이 과정을 더티 체킹(Dirty Checking)이라고 합니다.
@Transactional
public void updateMemberName(Long id, String newName) {
 Member member = memberRepository.findById(id).orElseThrow(
 () -> new IllegalStateExcetion("존재하지 않는 유저 입니다.")
 ); // 영속성 컨텍스트가 관리 시작
 
 // member.updateName()만 호출했을 뿐이고, update 쿼리는 없는 상황!
 member.updateName(newName); 
} // 👈🏻 트랜잭션이 끝나는 이 시점에 JPA가 변경을 감지하고 UPDATE 쿼리를 날려준
다.

3. 쓰기 지연(TransactionalWrite-Behind)

  • 동작 원리:
    1. memberRepository.save() 호출되면, 해당 엔티티는 1차 캐시에 저장되고, JPA는 이 엔티티를 DB에 반영하기 위한 INSERT SQL을 생성하여 차곡차곡 모아둡니다.
    2. UPDATEDELETE 쿼리도 마찬가지로 이 저장소에 쌓입니다.
    3. 트랜잭션이 커밋되는 순간, JPA는 모아뒀던 모든 SQL들을 한 번에 DB로 보냅니다. (이 과정을 Flush라고 합니다.)
  • 장점:
    SQL을 하나씩 보내지 않고 모았다가 한 번에 처리하므로, 네트워크 비용을 줄이고 DB
    와 상호작용하는 횟수를 최소화하여 성능을 최적화할 수 있습니다. (e.g., JDBC 배치
    기능 활용 가능)

📌 Flush란

Flush란 영속성 컨텍스트의 변경 내용을 DB에 동기화하는 것을 말합니다. Flush는 영속성 컨텍스트의 '쓰기 지연 SQL 저장소'에 쌓인 SQL들을 데이터베이스에 전송하여, 컨텍스트의 상태와 DB의 상태를 맞추는 작업이고, 트랜잭션 커밋과는 다릅니다!

Flush는 DB에 SQL을 보내는 것일 뿐, 트랜잭션을 확정(Commit)하는 것은 아닙니다. 즉, 원래대로라면 쓰기 지연으로 인해 모아두었던 SQL을 트랜잭션이 끝나는 시점에 한꺼번에 DB로 보내지만, Flush를 사용하면 그 시점에 바로 SQL을 DB로 보내게 됩니다.

⚠️ 단, Flush를 한다고 하더라도 여전히 트랜잭션으로 관리가 되고 있는 상태이기 때문에 트랜잭션 롤백 시, Flush한 데이터도 롤백됩니다.

profile
반갑습니다!

0개의 댓글