JPA

[JPA] 영속성 컨텍스트 PersistenceContext

솔솔 2021. 6. 29. 13:10
반응형

영속성 컨텍스트란?

- JPA에서 빼놓을 수 없는 가장 중요한 용어

- 엔티티를 영구 저장하는 환경

- EntityManager.persist(entity); persist는 우리가 DB에 저장하는 것으로 알고있지만 실제로는 엔티티를 영속성 컨테스트라는 곳에 저장하는 것

EntityManager가 생성되면 영속성 컨텍스트가 하나 생성된다.

 

엔티티의 생명주기

  • 비영속 (new/transient) : 영속성 컨텍스트와 전혀 관계없는 새로운 상태
//객체를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");

 

  • 영속 (managed) : 영속성 컨텍스트에 관리되는 상태

EntityManager생성 후 member 영속상태로 변경 (JPA 관리하는 상태)

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

//객체를 저장한 상태(영속) / DB가 처리되는 시점이 아님
em.persist(member);

 

  • 준영속 (detached) : 영속성 컨텍스트에 저장되었다가 분리된 상태 / 영속 -> 준영속

 ** 1차 캐시를 날려버리는 것

 준영속 상태로 만드는 방법

//회원 엔티티를 영속성 컨텍스트에서 분리 / 준영속 상태

//특정 엔티티만 준영속 상태로 전환
em.detach(entity);

//영속성 컨텍스트를 완전히 초기화
em.clear();

//영속성 컨텍스트를 종료
em.close();

 

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

 

영속성 컨텍스트의 이점

1. 1차 캐시

//비영속
Member member = new Member();
member.setId(101L);
member.setName("HiHi");
			
//영속 (DB가 처리되는 시점이 아님)
System.out.println("======Before");
em.persist(member);
System.out.println("======After");
			
Member findMember = em.find(Member.class, 101L);
System.out.println("em.find.id = " + findMember.getId());
System.out.println("em.find.name = " + findMember.getName());
			
// 커밋
tx.commit();

로그 시점을 보면 find를 했는데 select문 쿼리가 없다..!

그 이유는 영속성 컨텍스트에서 1차 캐시를 지원하기 때문이다. 위에 persist를 이용하여 저장한 데이터를 캐시에 담아두고있다가 캐시에 값이 존재하면 그 값을 반환해준다.

 

캐시에 데이터가 없을 경우, DB 조회 후 캐시에 저장하고 반환해줌으로서 매번 DB를 조회 안해도 된다.

 

2. 동일성(identity) 보장

Member a = em.find(Member.class, 101L);
Member b = em.find(Member.class, 101L);
			
System.out.println("a == b ? " + (a == b));

Member a와 Member b는 같은 값을 검색했을 때 동일할까?

정답은 true!

1차 캐시로 반복 가능한 읽기 등급의 트랜잭션 격리 수준을 데이터베이스가 아닌 애플리케이션 차원에서 제공

 

3. 트랜잭션을 지원하는 쓰기 지연 (transactional write-behind)

DB에 저장하기위해 persist로 member의 값을 보내지만 바로 DB에 저장되는 것이 아니고 쓰기 지연 SQL 저장소에 쿼리를 생성해서 저장해두고 transaction.commit() 시점에 쿼리를 날려 저장해준다!

 

4. 변경 감지 (Dirty Checking)

Member member = em.find(Member.class, 101L);
member.setName("zzzz");

기존 같으면 update를 해줘야하지않을까? 생각이 들지만 JPA는 값만 바뀌어도 자동으로 감지해서 update문을 자동으로 작성해줍니다!

너무 기똥찬거 아닌가요,,,? :o

알고보니 커밋되는 시점에서 JPA가 1차 캐시에 담긴 값과 스냅샷 값이 다른게 있는지 비교해준 후 다르다면 update문을 만들어준다고해요!! JPA 똑똑이!!!

 

5. 지연 로딩 (Lazy Loading)

  1) 지연 로딩 : 객체가 실제 사용될 때 로딩

     -> 값을 조회할 때 필요한 값을 바로 조회해오는 것

  2) 즉시 로딩 : JOIN SQL로 한번에 연관된 객체까지 미리 조회

     -> 근데 조회를 해올 때 매번 같은 값을 가져오면 즉시 로딩 사용하는게 낫기 때문에 옵션으로 변경 가능

지연 로딩과 즉시 로딩은 옵션으로 변경 가능하며, 주로 지연 로딩으로 구현해두고 최적화가 필요할 때만 변경

 

 

인강으로 공부하면서 작성하는 글로 잘못된 정보가 있을 수도 있습니다! 잘못된 정보가 있을 시 댓글달아주세요 : 0

반응형