[JPA] 영속성 컨텍스트(Persistence Context)

2021. 9. 28. 16:23[ 백엔드 개발 ]/[ Spring ]

속성 컨텍스트 관련 주요 용어

[Entity]

테이블과 매핑되는 객체이다.

 

[EntityManagerFactory]

EntityManager를 생성해주는 factory 성질을 갖는 Bean이다. Thread-safe하게 구현되어 있어서 여러 쓰레드가 동시에 접근해도 무방하다.

 

[EntityManager]

Entitiy와 관련된 일들을 담당한다. 즉, Entity를 저장하고, 수정하고, 삭제하고, 조회하는 (CRUD) 등 Entity와 관련된 모든 일을 처리한다. Thread-safe 하지 않기 때문에 EntitiyManagerFactory를 통해서 계속해서 새로운 EntityManager를 생성하도록 해서 단일 쓰레드가 EntitiyManager에 접근하도록 한다.

 

참고) JPA는 인터페이스일 뿐이며 이 포스팅에서 설명하는 것은 관계형 데이터베이스와 연관지었을 때 해당되는 설명이다. NoSQL을 사용할 경우에는 해당되지 않으며 Entity라는 용어 대신 Document라는 용어를 사용한다.

 

 

Spring Boot에서는 연동모듈로 spring-boot-starter-data-jpa를 지원하며 Auto Configuration이 적용된다.

 

 

 

 

Entity Manager 획득 과정

 

김영한 _ 자바 ORM 표준 JPA 프로그래밍

 

 

spring-boot-starter-data-jpa 연동모듈로 인해 WAS안에서 EntityManagerFactory와 EntityManager가 Bean으로 동작한다.

 

[획득 과정]

1) 요청이 오면 EntityManagerFactory가 각각의 요청마다 EntityManager를 만들어 준다. EntityManager는 Thread-Safe하지 않기 때문에 요청마다 EntityManager가 할당된다.

2) EntityManager가 DB와의 커넥션을 위해서 connection pool에서 커넥션을 가져온다. 실질적으로는 DB에 트랜잭션 commit을 발생시켜야 할 때 커넥션을 가져와서 사용한다. 즉, 실질적으로 필요할 때 가져온다.

 

 

 

 

영속성 컨텍스트란?

- JPA를 이용하는데 가장 중요한 요소이며 엔티티를 관리하는 공간이다.

- 1차 캐시를 두고 변경이 감지된 엔티티만을 쿼리한다.

 

 

[특징]

김영한 _ 자바 ORM 표준 JPA 프로그래밍

 

- EntityManager는 영속성 컨텍스트의 1차 캐시에서 Entitiy를 key-value로 관리하기 때문에, Entity는 식별자 값을 반드시 가져야한다. 즉, Entity 객체에는 @Id 가 붙은 필드가 반드시 있어야 한다.

 

- Hibernate는 트랜잭션을 커밋하는 순간 영속성 컨텍스트에 새로 저장된 엔티티를 DB에 반영한다. 이를 JPA에서는 FLUSH라고 한다. 즉, FLUSH를 통해 영속성 컨텍스트의 변경 내용을 DB에 동기화하고, 이때 등록, 수정, 삭제한 엔티티를 DB에 반영한다.

 

 

[속성 컨텍스트가 엔티티를 관리함으로 얻는 이점]

- 1차 캐시

- 동일성 보장

- 트랙잭션을 지원하는 쓰기 지연

- 변경 감지(Dirty checking)

- 지연 로딩(LAZY fetch)

 

 

 

Entity의 라이프사이클(생명주기)

 

Entity는 크게 4가지 상태를 갖는다.

 

- 비영속 (new / transient) : 영속성 컨텍스트에서 관리되지 않는 상태

- 영속 (managed) : 영속성 컨텍스트로 들어가 관리되기 시작한 후부터의 상태

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

- 삭제 (removed) : 영속성 컨텍스트에서 삭제하고 DB에서도 삭제된 상태

 

 

 

영속성 컨텍스트에서 CRUD 절차

1. 저장

김영한 _ 자바 ORM 표준 JPA 프로그래밍

 

 

- persist()로 인해 영속성 컨텍스트 안에 새로 Entitiy가 들어오게 되면 쓰기 지연 저장소에 INSERT 쿼리가 저장되고 1차 캐시에 keyu-value 쌍으로 Entitiy가 저장된다.

- transation에 커밋이 발생하면 Flush가 발생하고 쓰기 지연 저장소에 저장된 INSERT 쿼리가 실행됨으로써 DB에 반영된다.(DB와 동기화 발생)

 

 

2. 조회

1) 1차 캐시를 이용한 조회

 

김영한 _ 자바 ORM 표준 JPA 프로그래밍

 

find()를 통해 1차 캐시에서 우선적으로 조회하고 1차 캐시에 해당 Entitiy가 있다면 DB 까지 가지 않고도 Entitiy를 조회할 수 있다.

 

 

2) DB 접근을 통한 조회

김영한 _ 자바 ORM 표준 JPA 프로그래밍

 

만약 clear() 등을 통해 영속성 컨텍스트의 1차 캐시에 Entitiy가 없다면(cache miss) select 문을 통해 DB에서 직접 조회한다. 그리고 1차 캐시에 캐싱 후 결과를 반환한다.

 

 

 

3. 수정

영속성 컨텍스트 안에 있는 Entity의 필드 값을 바꿔 놓기만 하면 트랜잭션이 commit할 때 DB에 반영된다. 이때 스냅샷을 비교하면서 변경사항이 발생한 Entity에 대해서만 DB에 반영한다.

 

[변경감지(dirty checking)] *** DB와 캐시를 동기화 시키는 방법!!!

JPA 는 엔티티를 영속성 컨텍스트에 보관할 때, 최초 상태를 복사해서 저장해 두는데 이것을 스냅샷이라 한다. 그리고 FLUSH 시점에 스냅샷과 엔티티를 비교해서 변경된 엔티티를 찾는다. 만일 스냅샷과 비교하여 변경된 내용이 있을 경우 UPDATE 쿼리를 수행한다. 단, 변경 감지는 영속성 컨텍스트가 관리하는 영속 상태의 Entity에만 적용이 된다.

 

 

김영한 _ 자바 ORM 표준 JPA 프로그래밍

 

 

 

 

4. 삭제

영속성 컨텍스트에서 Entity를 삭제해 주기만 하면 트랜잭션이 커밋되면서 DELETE 쿼리가 수행된다.

 

 

 

 

* 위 일련의 과정들(조회, 삭제, 삽입 등)은 transaction 안에서 수행되어야 한다. 즉, Entity 객체의 필드값을 바꾸는 과정, 또는 remove 호출은 트랜잭션 안에서 진행되어야 한다. 그래야 트랜잭션이 commit 되면서 실제 DB 에 쿼리가 수행되고 반영된다.

 

 

 

참고

- JPA 개요 : https://jh-labs.tistory.com/49