본문 바로가기

JPA

[JPA] 영속성 컨텍스트


JPA에서 가장 중요한 것이 2가지 있습니다.

1. 객체와 관계형 데이트베이스 매핑

2. 연속성 컨텍스트

입니다.

 

EntityManagerFactory


요청이 들어올 때마다 EntityManager를 생성해 줍니다.

EntityManager


내부적으로 DatabaseConnection을 사용하여 DB에 접근하게 됩니다.

영속성 컨텍스트에 접근할 수 있습니다.

영속성 컨텍스트


JPA를 이해하는데 가장 중요한 용어입니다.

엔티티를 영구 저장하는 환경이라는 뜻입니다.

EntityManager.persist (entity);

  • DB에 저장한다는 것이 아니라 persist는 영속성 컨텍스트에 저장합니다.

영속성 컨텍스트는 논리적인 개념입니다.

엔티티 매니저를 통해서 영속성 컨텍스트에 접근합니다.

엔티티 생명주기


  1. 비영속 ( new/transient )
    • 영속성 컨텍스트와 전혀 관계가 없는 새로운 상태입니다.
  2. 영속 ( managed )
    • 영속성 컨텍스트에 관리되는 상태입니다.
  3. 준영속 ( detached )
    • 영속성 컨텍스트에 저장되었다가 분리된 상태입니다.
  4. 삭제 ( removed )
    • 삭제된 상태입니다.

 

비영속


객체만 생성한 상태입니다.

Member member = new Member();
member.setId( );
member.setUsername( );

영속


객체를 저장한 상태입니다.

이 상태에서는 DB에 저장되지 않습니다.

쿼리나 나가는 경우에는 transaction commit을 하는 경우입니다.

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

준영속


영속성 컨텍스트에서 지웁니다.

em.detach(member);

삭제


실제 DB에서 삭제를 요청합니다.

em.remove(member);

 


 

엔티티 조회, 1차 캐시


1차 캐시를 영속성 컨텍스트라고 생각해도 무방합니다.

현재 영속성 컨텍스트에는 member 객체 생성 후 em.persist(member)를 한 상황 즉, 엔티티 영속 상태입니다.

 

1차 캐시


Key (@Id)는 ID(member1) / Value (Entity)는 member 객체 자체입니다.

em.persist(member1) // 1차 캐시에 저장
em.find(Memeber.class, “member1”) // 1차 캐시에서 조회

em.find( )를 하는 순간 DB에서 데이터를 찾는 것이 아니라 1차 캐시에서 먼저 조회하며, 있으면 캐시에서 있는 값을 그대로 전달합니다.

 

데이터 베이스에서 조회


만약, 1차 캐시에 없는 member2를 조회할 경우입니다.

1차 캐시에서 조회 -> 없음 -> DB에서 member2를 조회 -> 있음 -> member2를 1차 캐시에 저장 -> member2 반환 -> 이후에 member2를 조회 -> 영속성 컨텍스트에 있는 1차 캐시에서 memeber2를 조회

 

EntityManager는 보통 Database Transaction단위로 만들어집니다.

즉, DB Transaction이 끝날 때 같이 종료시킵니다. 이것은 고객 요청이 하나 들어와서 비즈니스가 끝나버리면 영속성 컨텍스트를 삭제합니다. (1차 캐시도 삭제) 

→ 비즈니스 로직이 굉장히 복잡할 경우에는 도움이 되지만 그 외에는 큰 도움이 되지 않습니다.

 

영속 엔티티의 동일성 보장


Member member1 = em.find(“member1”);
Member member2 = em.find(“member1”);
System.out.println(member1 == member2);
-----
true

 

엔티티 등록


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

em.persist(memberA);
em.persist(memberB);
// 여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.

transaction.commit() // 커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.

 

persist할 때마다 쓰기 지연 저장소와 1차 캐시에 차곡차곡 쌓입니다.

 

언제 DB에서 나갈까?

transaction.commit( )하는 시점에 쓰기지연 저장소에서 flush commit을 하게 됩니다.

그때 DB에 쓰기 지연 저장소에 있던 SQL 쿼리문이 한꺼번에 나가게 됩니다.

 

엔티티 수정


변경 감지

Member member = em.find(Member.class, “memberA”);

찾은 후 값 변경

member.setName(“ZZZZ”);

 

여기서 em.persist(member) 혹은 em.update(member)를 하지 않습니다.

값 변경 후 commit하게 되면 update쿼리가 나가게 됩니다.

변경 과정

스냅샷이란?

영속성 컨텍스트에 최초로 들어온 상태를 스냅샷 처럼 떠논 것을 말합니다.

만약 memeberA를 변경하고 commit을 하게 된다면, 그 시점에 내부에서 flush가 호출되면서 JPA가 엔티티와 스냅샷을 비교합니다. 그리고 바뀐 것이 있으면 UPDATE쿼리를 쓰기 지연 저장소에 만들어 둡니다. 마지막으로 이것을 DB에 반영하고 commit을 하게됩니다.

 

엔티티 삭제


COMMIT시점에 DB에 DELETE 쿼리를 나가게 됩니다. 


 

 

출처

https://www.inflearn.com/course/ORM-JPA-Basic/dashboard

 

'JPA' 카테고리의 다른 글

[JPA] Auditing  (0) 2021.11.16
[Spring Boot] JPA application.yml (properties)기능  (0) 2021.11.08
[JPA] 쿼리 작성 법  (0) 2021.01.21
[JPA] 페치 조인(fetch join)의 한계  (0) 2021.01.21
[JPA] 페치조인(fetch join)이란?  (0) 2021.01.21