본문 바로가기
JPA&SpringBoot

영속성 컨텍스트와 1차 캐시

by 민휘 2023. 5. 18.

영속성 컨텍스트는 JPA에서 엔티티의 상태를 관리하기 위한 논리적인 작업 영역이다. 영속성 컨텍스트는 엔티티 매니저(Entity Manager)에 의해 생성되고 관리된다.

 

 

영속성 컨텍스트의 특징

  • 1차 캐시: 영속성 컨텍스트에 의해 관리되는 엔티티 객체의 캐시. 반복적인 데이터베이스 조회를 줄이고, 성능을 향상시킬 수 있다.
  • 지연 로딩: 연관된 엔티티를 실제로 사용할 때까지 로딩을 지연시키는 기능이다. 필요한 시점에 필요한 데이터만 로드하여 성능을 최적화할 수 있다. 프록시로 구현한다.
  • 트랜잭션 관리: 영속성 컨텍스트에 저장된 엔티티는 트랜잭션이 커밋될 때까지 변경을 모아두고, 트랜잭션이 롤백되면 변경된 내용을 취소한다. 데이터 일관성을 유지할 수 있다.
  • Dirty Checking: 엔티티의 상태 변화를 추적하여 변경된 속성만을 데이터베이스에 자동으로 반영한다.

 

 

영속성 컨텍스트의 구조

  • 1차 캐시 : 엔티티 인스턴스들이 1차 캐시에 저장되어 관리된다. 1차 캐시 안에서 엔티티와 식별자 간의 매핑을 유지한다. 이를 통해 엔티티의 식별자를 사용하여 올바른 엔티티 인스턴스를 찾을 수 있다. 또한 애플리케이션에서 쓰기 작업이 일어난 경우 1차 캐시에 즉시 반영된다.
  • 쓰기 지연 SQL 저장소: 트랜잭션이 커밋될 때까지 만들어둔 SQL을 모아두는 곳이다. 트랜잭션이 커밋되면 여기에 있는 변경 내용이 데이터베이스에 일괄적으로 반영된다.

 

 

애플리케이션에서 쓰기 동작이 발생했을 때 영속성 컨텍스트에서 일어나는 일

  1. 데이터가 변경되면 즉시 1차 캐시에 반영한다.
  2. 변경 사항이 지연 SQL 저장소에 저장된다.
  3. Transaction이 commit되면 Flush가 발생한다.
  4. 지연 SQL 저장소에 있는 SQL문을 DB에 요청한다.

 

 

1차 캐시 기능 확인하기

@RunWith(SpringRunner.class)
@SpringBootTest
class MemberRepositoryTest {

    @Autowired MemberRepository memberRepository;

    @Test @Transactional
    public void testMember() throws Exception {
        // given
        Member member = new Member();
        member.setUsername("A");

        // when
        Long savedId = memberRepository.save(member);
        Member findMember = memberRepository.find(savedId);

        // then
        assertThat(findMember.getId()).isEqualTo(member.getId());
        assertThat(findMember.getUsername()).isEqualTo(member.getUsername());
        assertThat(findMember).isEqualTo(member); // 같은 영속성 컨텍스트 안에서는 id가 같으면 같은 엔티티로 인식. 1차 캐시에서 찾아옴.
    }

}

save 호출이 발생했을 때 member 엔티티가 1차 캐시에 저장되고, find로 조회하면 1차 캐시에서 엔티티를 조회한다. 그런데 테스트에서 @Transactional은 테스트가 끝나면 자동 롤백된다. 그래서 flush가 발생하지 않으므로, 테스트 과정에서 insert나 select는 발생하지 않는다.

 

 

flush가 발생하도록 하고 싶다면 테스트 메소드 위에 @Rollback(value = false)를 추가하면 된다. 테스트가 끝나고 트랜잭션이 커밋되므로 member가 insert된다. 단, 이때에도 save나find를 호출했을 때는 1차 캐시에서 작업이 일어나므로 즉시 sql이 실행되지는 않는다.