영속성 컨텍스트 (persistence context)

박영준·2023년 1월 28일
0

JPA

목록 보기
6/8

1. 정의

  • Entity를 영구 저장 하는 환경

  • 어플리케이션(일단 '자바 코드 그 자체'라고 간주하기)이 DB에서 꺼내온 데이터 객체를 보관

  • EntityManager 를 통해 Entity를 저장/조회할 때, 영속성 컨텍스트에 접근/관리 가능

  • EntityManager 를 생성할 때, 하나 만들어짐

  • EntityManage 마다 개별적으로 부여되는, 어떠한 논리적 공간

    • 자바의 엔티티 객체를 영속성 컨텍스트(EntityManager마다 가지고 있는)라는 공간에다 넣고 빼고 하면서 사용
    • “영속화 한다” = “EntityManager가 자기의 영속성 컨텍스트에 넣어준다”
  • JPA를 이해하는데 가장 중요한 용어

1) Entity

(1) Entity의 생명주기 (JPA Entity의 상태)

① 비영속 (New)

// 엔티티(minsook)를 생성
Member minsook = new Member();

member.setId("minsook");
member.setUsername("민숙");
  • 영속성 컨택스트와 관계가 없는 새로운 상태
  • 해당 객체의 데이터가 그냥 Java 객체인 상태(실제 DB의 데이터와는 관련 X)
  • 엔티티 객체를 생성 O,
    그러나 아직 영속성 컨텍스트에 저장은 X

② 영속 (Managed)

// 엔티티 매니저를 통해 영속성 컨텍스트에 해당 엔티티(minsook)를 저장
	// entityManager.persist(minsook); 으로 해도 동일함
em.persist(minsook);
  • EntityManager 를 통해, Entity를 영속성 컨텍스트에 저장한 상태 → "영속성 컨텍스트에 의해 관리된다."는 뜻
  • JPA가 데이터의 생성, 변경...등을 추적하면서, 필요하면 DB에 반영
  • 식별자 값을 가진다.(필수적으로!)

③ 준영속(Detached)

// 엔티티를 영속성 컨텍스트에서 분리해, 준영속 상태로 만든다.
em.detach(minsook);

// 영속성 콘텍스트를 비워도, 관리되던 엔티티는 준영속 상태가 된다.
em.clear();

// 영속성 콘텍스트를 종료해도, 관리되던 엔티티는 준영속 상태가 된다.
em.close();
  • 영속성 컨택스트에서 관리되다가 분리된 상태
    (= 영속성 컨텍스트가 관리하던 영속 상태의 Entity를 더이상 관리하지 않으면 준영속 상태가 됨)
  • 준영속 상태
    • 영속성 컨텍스트가 제공하는 어떠한 기능(1차 캐시, 쓰기 지연, 변경 감지, 지연 로딩을 포함한 )도 동작하지 X
    • 식별자 값을 가진다.

④ 삭제(Removed)

em.remove(minsook)
  • Entity 가 영속성 컨텍스트와 DB 에서 삭제된 상태

2. 특징

1) 1차 캐시

// 1차 캐시에서 조회하는 방법
	// Map의 형태로 만들어짐 →  (value에는 해당 entity값, key에는 id값) 
		// em.find(엔티티 클래스 타입, 식별자 값);
Member member = em.find(Member.class, "member1");
  • 영속성 컨텍스트 내부에 있는 캐시를 '1차 캐시'라고 하며,
    영속 상태의 엔티티를 1차 캐시에 저장

  • 데이터는 1차 캐시가 아닌 다른 곳에 있는 경우가 多
    → 그래서, DB를 이용하는 작업은 상대적으로 부하와 비용이 심하다.

  • 부하가 심한 작업을 자주하는 것을 줄이기 위해, 영속성 컨텍스트 내부에 1차캐시를 둔다.
    (= 데이터를 조회할 때마다, DB로 SQL쿼리(“SELECT * FROM….”과 같은)를 내는 일은 막아야 한다는 것)

  • 1차 캐시에 데이터가 저장되면, memberB를 find 하는 요청이 다시 들어와도, 굳이 DB로 다녀올 필요 X
    → 즉, 전에 불러온 것을 다시 빠르게 사용 할 수 있도록 그걸 담아두는 공간이 '영속성 컨텍스트'

2) 쓰기 지연 SQL 저장소

entityManager.flush();
  • em.find(member)를 사용해 member를 저장해도, 바로 INSERT SQL이 DB에 보내지는 것이 X
    → EntityManager 는 트랜잭션을 커밋하기 직전까지 내부 쿼리 저장소에 INSERT SQL을 모아두고,
    트랜잭션을 commit 할 때 모아둔 쿼리를 DB에 보낸다.

  • MemberA, MemberB를 생성할 때마다 DB 를 다녀오지 않도록,
    효율성을 위해 내부에 “쓰기 지연 SQL 저장소”를 둔다.

  • flush

    • JPA가 트랜잭션을 commit하는 순간, 영속성 컨텍스트에 새로 저장된 Entity(변경 내용)를 DB에 반영하는 것
      → 결론적으로, Entity는 영속성 컨텍스트와 데이터베이스에 저장된다.
    • 영속성 컨텍스트의 엔티티를 지우는게 아니라 변경 내용을 데이터베이스에 동기화하는 것
    • em.flush()

    참고: 영속성 컨텍스트 (persistence context) - “영속화 한다”

    참고: SQL (Structured Query Language, 구조적 질의 언어)

3) Dirty Checking 로 변경 감지

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

Member member = em.find(Member.class, "member1");
member.setName("노영삼");

transaction.commit();
  • JPA 는 '1차 캐시'와 '쓰기 지연 SQL 저장소'를 이용해서, 데이터 변경을 감지해서 자동 수정
    (DirtyChecking: 트랜잭션 안에서 엔티티의 변경 발생 시, 변경 내용을 자동으로 DB에 반영하는 JPA의 특징 ≒ 수정)

  • 변경 감지 : 영속성 컨텍스트가 관리하는 영속 상태의 엔티티만 적용

4) 동일성 보장

데이터의 어플리케이션 단의 동일성을 보장
영속 엔티티의 동일성 보장

Member member1 = em.find(Member.class, "minsook");
Member member2 = em.find(Member.class, "minsook");
System.out.println(member1 == member2) 	// true

동일성 비교 : 실제 인스턴스 & 인스턴스가 가지고 있는 값이 같다. == 을 사용해 비교
동등성 비교 : 실제 인스턴스는 다를 수 있지만, 인스턴스가 가지고 있는 값이 같다. equals() 메소드를 구현해서 비교

5) 식별자 값

Entity의 영속 상태에는 식별자 값이 반드시 있어야 한다.
→ 영속성 컨텍스트가 Entity를 식별자 값으로 구분하기 때문

참고: 식별자


참고: JPA 영속성 컨텍스트란?
참고: JPA 더티 체킹(Dirty Checking)이란?
참고: [Spring JPA] 영속성 컨텍스트(Persistence Context)

profile
개발자로 거듭나기!

0개의 댓글