[JPA] 영속성 컨텍스트
영속성 컨텍스트
정의
An EntityManager instance is associated with a persistence context. A persistence context is a set of entity instances in which for any persistent entity identity there is a unique entity instance. Within the persistence context, the entity instances and their lifecycle are managed. The EntityManager API is used to create and remove persistent entity instances, to find entities by their primary key, and to query over entities.
영속성 컨텍스트는 모든 영속 엔티티 ID에 대해 고유한 엔티티 인스턴스가 있는 엔티티 인스턴의 집합이다. 영속성 컨텍스트에서 각 엔티티 인스턴스와 이들의 생명주기는 관리된다. 엔티티 매니저를 통해서 영속 앤티티를 생성, 제거할 수 있으며 기본키를 사용하여 조회할 수 있다.
영속성 컨텍스트는 모든 엔티티가 DB에서 가져오거나 DB에 저장되는 1차 캐시이다.
쉽게 정리하면 엔티티를 저장하고 관리하는 환경 자체를 말한다. 그리고 애플리케이션과 데이터베이스 사이에서 객체를 보관하며 1차 캐시 역할을 수행한다.
엔티티 매니저와 팩토리
엔티티 매니저 팩토리 (Entity Manager Factory)
엔티티 매니저를 생성하는 역할을 수행한다. DB 당 하나만 존재하며 여러 스레드에서 동시에 접근해도 동시성 문제가 발생하지 않는다. JPA 구현체(hibernate 등..)은 앤티티 매니저 팩토리를 생성할 때, 커넥션 풀도 같이 생성해둔다.
엔티티 매니저 (Entity Manager)
엔티티 매니저는 영속성 컨텍스트에 접근할 수 있는 인터페이스이다. 엔티티 매니저를 통해서 우리가 필요로 하는 연산을 수행할 수 있다. 엔티티 매니저 팩토리와 다르게 thread safe하지 않기 때문에 동시성 문제가 존재한다. 때문에 스레드간 엔티티 매니저를 공유하면 절대 안된다.
엔티티의 생명주기
이제 영속성 컨텍스트에서 관리되는 엔티티들의 생명 주기에 대해서 알아보자.
영속
엔티티가 영속성 컨텍스트에서 관리될 때 비로써 연산 결과를 최종적으로 DB에 반영할 수 있다. 이렇게 영속성 컨텍스트에 관리되는 상태를 영속상태 라고 한다.
비영속
영속성 컨텍스트와 전혀 관련이 없는 상태를 말한다. 이 상태의 엔티티는 값이 변경되거나, 삭제되더라도 DB에 반영되지 않는다.
준영속
영속성 컨텍스트에서 관리되다가 분리된 상태를 말한다. 비영속과 마찬가지로 엔티티가 변경되도 DB에 반영되지 않는다.
삭제
영속성 컨텍스트로부터 삭제된 상태를 말한다.
지금까지 영속성 컨텍스트에서 관리되는 엔티티들의 생명주기에 대해서 알아봤다. 그렇다면 영속성 컨텍스트에 관리되면 어떤 이점이 있을까?
이제 이에 대해서 알아보자.
장점
1차 캐시
앞에 영속성 컨텍스트 정의에서 설명했듯이 영속성 컨텍스트는 애플리케이션과 DB사이에서 1차 캐시 역할을 수행한다. 만약 영속성 컨텍스트에 조회하고자 하는 데이터가 있다면 DB를 거치지 않고도 값을 읽어올 수 있기 때문에 약간의 성능 향상이 있을 수 있다.
동일성
영속성 컨텍스트는 1차 캐시로서 REPEATABLE READ 등급의 트랜잭션 격리 수준을 애플리케이션 차원에서 제공해준다. (트랜잭션 격리 수준에 대해서 잘 모른다면 참고을 참고하자.)
쓰기 지연
만약 트랜잭션 안에서 모든 연산마다 DB에 쿼리가 하나씩 나간다면 어떨까? 분명 성능이 좋지 못할 것이다. 영속성 컨텍스트는 트랜잭션 안에서 수행되는 연산들을 쓰기 지연 SQL 저장소에 모아두었다가 flush()
가 호출되면 한번에 DB에 쿼리를 보낸다.
변경 감지
영속성 컨텍스트는 처음 1차 캐시에 엔티티를 저장하는 시점의 엔티티의 상태를 스냅샷으로 저장해둔다. 그리고 flush()
가 호출될 때 현재 상태와 스냅샷을 비교하여 변경된 부분을 쿼리로 생성하고 DB에 한번에 쿼리를 보낸다. 때문에 개발자가 변경된 부분에 대한 수정 쿼리를 일일이 작성할 필요가 없다.
지연 로딩
지연 로딩 세팅을 해두면 엔티티를 사용하기 전까지는 proxy 객체를 대신 넣어두게 된다. 때문에 실제로 엔티티가 사용되기 전까지 DB에 쿼리를 보내지 않고 실제 사용 시점에 쿼리를 보내게 된다.