JPA

[JPA] 영속성 컨텍스트

곱창국수 2022. 8. 22. 16:56

엔티티의 생명주기

  • 비영속 : 영속성 컨텍스트와 전혀 관계가 없는 상태
  • 영속 : 영속성 컨텍스트에 관리되는 상태
  • 준영속 : 영속성 컨텍스트에 저장되었다가 분리된 상태
  • 삭제 : 삭제된 상태

생명주기

비영속

단순히 객체만 생성한 상태이다.

Member member = new Member();
member.setId("member1");
member.setName("회원1");
영속

객체를 생성하고 영속 컨텍스트 안에 객체를 저장한 상태이다.

// 비영속
Member member = new Member();
member.setId("member1");
member.setName("회원1");

EntityManager em = emf.createEntityManager();
em.getTransaction().begin();

// 영속
em.persist(member);
준영속, 삭제
//회원 엔티티를 영속성 컨텍스트에서 분리, 준영속 상태 
// 특정 엔티티만 준영속 상태로 전환
em.detach(member);
// 영속성 컨텍스트를 완전히 초기화
em.clear();
// 영속성 컨텍스트를 종료
em.close();

//객체를 삭제한 상태(삭제) 
em.remove(member);

 

영속성 컨텍스트의 이점

  • 1차 캐시
  • 동일성 보장
  • 트랜잭션을 지원하는 쓰기 지연
  • 변경 감지 ( dirty checking )
  • 지연 로딩( Lazy Loading )
1차 캐시

내부에 1차 캐시를 가지고 있다. 트랜잭션 단위의 매우 짧은 캐시이다. 트랜잭션 단위이기때문에 사실상 성능상으로 크게 나아지는것은 아니다.

 

조회

Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
//1차 캐시에 저장됨
em.persist(member);
//1차 캐시에서 조회
Member findMember = em.find(Member.class, "member1");

1차 캐시에서 먼저 조회할 값을 찾고, 없으면 디비에 접근하여 1차캐시에 저장하여 값을 리턴해준다.

 

동일성 보장

 

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

 

쓰기 지연

persist()에서 insert되지 않고, 실제로 transaction.commit이 되는 순간 DB에 INSERT 쿼리가 날라간다.

EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
//엔티티 매니저는 데이터 변경시 트랜잭션을 시작해야 한다.
transaction.begin(); // [트랜잭션] 시작
em.persist(memberA);
em.persist(memberB);
//여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.
//커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
transaction.commit(); // [트랜잭션] 커밋

persist() 단계에서는 1차 캐시에 저장되고, 커밋이 일어나는 순간 직전에 flush되면서 실제 디비에 insert쿼리가 날라간다.

해당 기능으로 SQL버퍼에 쿼리를 담아 뒀다가 한번에 실행할 수 있다. 해당기능은 기존 MyBatis에서는 지원하지 않는 기능이다.

 

변경 감지 ( dirty checking )

영속성 컨텍스트안에 1차캐시에는 객체가 처음 들어왔을때의 정보를 스냅샷 형태로 저장하고 있다가, 변경 수정 사항이 있으면, commit되기 직전에 1차캐시의 데이터를 자동으로 비교하여 update를 날리는 기능이 있다.

변경감지