영속성 컨텍스트

영속성 컨텍스트란?

“엔티티를 영구 저장하는 환경”

  • 영속성 컨텍스트는 눈에 보이지 않는 논리적인 개념
  • 엔티티 매니저를 통해서 영속성 컨텍스트에 접근(영속성 컨텍스트 안에 엔티티 매니저 존재)

엔티티의 생명주기

비영속성

Member member = new Member();
member.setId("memeber1");
member.setUsername("회원1");
  • 객체를 생성만 해서 영속성 컨텍스트와는 관련이 없는 상태
  • 즉 영속성 컨텍스트와 전혀 관계가 없는 새로운 상태

영속

Member member = new Member();
member.setId("memeber1");
member.setUsername("회원1");

EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
// 객체를 생성한 상태(영속)
em.persist(member);
  • persist 메서드에 memeber 객체를 담아서 영속성 컨텍스트에 전달
  • 영속성 컨텍스트에 관리되는 상태

준영속, 삭제

Member member = new Member();
member.setId("memeber1");
member.setUsername("회원1");

EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(member);
// 영속성 컨텍스트에서 분리
em.detach(member)
// DB에서 삭제
em.remove(member)
  • detach 메서드로 member 객체를 영속성 컨텍스트에서 분리
  • 영속성 컨텍스트에 저장되었다가 분리된 상태

  • remove 메서드로 member 객체를 DB에서 삭제
  • 데이터베이스에서 삭제된 상태

영속성 컨텍스트의 장점

1차 캐시

1차 캐시

Member member = new Member();
member.setId("memeber1");
member.setUsername("회원1");

// 1차 캐시에 저장됨
em.persist(member);

// 1차 캐시에서 조회
Member findMember = em.find(Member.class, "member1");
  • 객체를 조회하면 먼저 1차 캐시에서 찾아보고 있으면 객체 반환

DB에서 조회

  • 만약 객체가 1차 캐시에 없으면 DB 조회 후 1차 캐시에 저장하고 객체 반환
  • 트랜잭션 단위로 캐시가 생성, 삭제되어서 사실 성능에 큰 차이는 없음

영속 엔티티의 동일성 보장

Member member = new Member();
member.setId("memeber1");
member.setUsername("회원1");

// 1차 캐시에 저장됨
em.persist(member);

// 1차 캐시에서 조회
Member a = em.find(Member.class, "member1");
Member b = em.find(Member.class, "member1");
System.out.println(a == b); // True
  • 1차 캐시로 반복 가능한 읽기 등급의 트랜잭션 격리 수준을 데이터베이스가 아닌 애플리케이션 차원에서 지원
  • JPA가 아니라 DB에서 쿼리로 불러왔다면 a != b로 False

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

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

transaction.begin(); // 트랜잭션 시작

em.persist(memberA);
em.persist(memberB);
// 여기까지 Insert SQL을 데이터베이스로 보내지 않음

// commit 하는 순간 Insert SQL을 데이터베이스로 보냄 
transaction.commit();

쓰기지연

  • 쓰기 지연 SQL 저장소에 INSERT SQL 쿼리 저장
  • 엔티티는 1차 캐시에 저장

commit

  • commit하는 순간 flush, 즉 모아둔 INSERT 쿼리랑 엔티티 전부 전송(버퍼랑 비슷한 개념)

변경감지(Dirty Checking)

변경감지

  • 따로 update하지 않아도 영속 컨텍스트 내의 1차 캐시에서 스냅샷(초기 엔티티)과 변경된 엔티티를 비교 후 UPDATE 쿼리 저장
  • 이후 한번에 자동으로 데이터베이스로 변경된 엔티티와 UPDATE 쿼리 보내줌

출처: 자바 ORM 표준 JPA 프로그래밍 - 기본편