영속성 컨텍스트는 엔티티를 영구 저장하는 환경이다.

em.persist(entity)

위 코드를 실행하면 entity 객체가 바로 DB 에 입력이 되는 것이 아니라, 영속성 컨텍스트로 등록이 되는 것이다.

EntityManager를 통해서 영속성 컨텍스트에 접근할 수 있다.

엔티티의 생명 주기

  • 비영속 (new/transient)
    영속성 컨텍스트와 전혀 상관 없는 새로운 상태
  • 영속 (managed)
    영속성 컨텍스트에 관리되는 상태
  • 준영속 (detached)
    영속성 컨텍스트에 저장되었다가 분리된 상태
    변경을 해도 변경감지(dirty checking)이 되지 않아 DB 에 반영되지 않는다.
  • 삭제 (removed)
    삭제된 상태

영속 상태란? 1차 캐시에 엔티티가 등록되어 관리되는 상태이다. 이 상태에서 같은 객체를 다시 한번 조회하게 되면, 굳이 DB에 select문을 보내서 값을 찾아오는 것이 아니라 1차 캐시상에서 값을 바로 가져온다. 그렇기 때문에 성능상의 이점도 있고, 마치 JAVA에서의 컬렉션에서 값을 꺼내오는 것처럼 엔티티의 동일성을 보장받게 된다.

영속성 컨텍스트의 장점

  • 1차 캐시
  • 동일성(identity) 보장
  • 트랜잭션을 지원하는 쓰기 지연 (transactional write-behind)
  • 변경 감지 (Dirty Checking)
  • 지연 로딩 (Lazy Loading)

1차 캐시

데이터베이스에 엔티티 조회 시, 1차 캐시에 찾는 객체가 있는지 확인 후 없을 경우 DB에서 select 문을 통해 찾아온다.

동일성 보장

1차 캐시로부터 찾은 객체는 서로 동일함이 보장된다.

Member a = em.find(Member.class, "member1");
Member b = em.find(Member.class, "member1");
System.out.println(a == b); //동일성 비교 true

트랜잭션을 지원하는 쓰기 지연

영속성 컨텍스트는 buffer의 역할을 한다. 변경사항이 생기면 쓰기 지연 SQL 저장소에 모아놨다가 트랜잭션을 커밋할 때 flush 되어 DB 에 반영된다.

EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();

transaction.begin(); // [트랜잭션] 시작
em.persist(memberA);
em.persist(memberB);
//여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.

//커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
transaction.commit(); // [트랜잭션] 커밋

변경 감지

영속성 컨텍스트는 flush 할 때 이전의 상태를 스냅샷(snapshot)으로 저장해놓고 변경사항을 체크해 업데이트를 해준다.

flush

  • 영속성 컨텍스트의 변경내용을 데이터베이스에 반영한다.
  • 영속성 컨텍스트를 비우지 않는다.
  • 트랜잭션이라는 작업 단위가 중요하므로, 커밋 직전에만 동기화하면 된다.

flush는 언제 발생할까?

  1. 변경 감지
  2. 수정된 엔티티 쓰기 지연 SQL 저장소에 등록
  3. 쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송 (등록, 수정, 삭제 쿼리)

flush 하는 방법

  1. em.flush()
  2. 트랜잭션 커밋
  3. JPQL 쿼리 실행

flush 모드 설정

em.setFlushMode(FlushModeType.COMMIT)
  • FlushModeType.AUTO
    커밋이나 쿼리를 할 때 플러시 (기본값)
  • FlushModeType.COMMIT
    커밋할 때만 플러시

준영속 상태

영속 상태의 엔티티가 영속성 컨텍스트에서 분리됬을 때(detached)의 상태이다.
영속성 컨텍스트가 제공하는 기능을 사용하지 못한다.

준영속 상태의 엔티티를 변경해도 변경 감지가 작동하지 않아서 DB에 반영되지 않는다.

준영속 상태로 만드는 방법

  1. em.detach(entity)
    특정 엔티티만 준영속 상태로 전환
  2. em.clear()
    영속성 컨텍스트를 완전히 초기화
  3. em.close()
    영속성 컨텍스트를 종료

참고 자료

profile
컴공학부생입니다.

0개의 댓글