영속성 관리


* 엔티티 매니저 팩토리 & 엔티티 매니저
엔티티 매니저 팩토리는 여러 스레드가 동시에 접근해도 안전하므로 서로 다른 스레드 간에 공유해도 되지만,
엔티티 매니저는 여러 스레드가 동시에 접근하면 동시성 문제가 발생하므로 스레드 간에 절대 공유하면 안된다.

1
2
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpabook");
EntitiManager em = emf.createEntityManger();

cs


데이터베이스 연결이 꼭 필요한 시점까지 커넥션을 얻지 않고 트랜잭션을 시작할 때 커넥션을 획득한다.

영속성 컨텍스트
- 엔티티 매니저 생성시 생성되는 엔티티 영구 저장 환경.
- 엔티티 매니저로 엔티티를 저장하거나 조회하면 엔티티 매니저는 영속성 컨텍스트에 엔티티를 보관하고 관리한다.

* 엔티티의 생명주기
비영속(New/Transient) : 영속성 컨텍스트와 전혀 관계 없는 상태. 엔티티 객체 생성후 저장되지 않은 상태.
영속(Managed) : 영속성 컨텍스트에 저장된 상태. 영속성 컨텍스트에 의해 관리된다.
준영속(Detached) : 영속성 컨텍스트에 저장되었다가 분리된 상태. 영속성 컨텍스트에 의해 관리되지 않는다.
삭제(Removed) : 삭제된 상태. 영속성 컨텍스트와 DB에서 삭제된 상태.

* 영속성 컨텍스트 특징
- 영속 상태는 식별자 값이 반드시 있어야 한다.
- 트랜잭션을 커밋하는 순간 영속성 컨텍스에 새로 저장된 엔티티를 DB에 반영한다. flush
- 장점) 1차 캐시, 동일성 보장, 트랜잭션을 지원하는 쓰기 지연, 변경감지, 지연로딩. (CRUD 통해 설명)

# 엔티티 조회 em.find(entity class, key)
1차 캐시 : 영속 상태의 엔티티 저장소로 Map 형태에 @Id로 매핑할 식별자와 엔티티 인스턴스 값을 저장한다.
동일성 보장 : 조회 쿼리 호출시 1차 캐시에서 엔티티를 찾고, 없으면 DB에서 조회하여 1차 캐시에 저장시킨 후 엔티티를 반환한다.
지연로딩 : 일대다 혹은 다대다 관계의 컬렉션을 실제 사용하는 시점까지 DB 조회를 지연한다. (자세한 내용은 다음 챕터에..)
- JPA는 1차 캐시를 통해 REPEATABLE READ 레벨의 트랜잭션 격리 수준을 DB가 아닌 애플리케이션 차원에서 제공한다는 장점이 있다.

# 엔티티 등록 : em.persist(entity)
트랜잭션을 지원하는 쓰기 지연 : 엔티티 메니저는 트랜잭션을 커밋하기 전까지 엔티티를 DB에 저장하지 않고 쓰기 지연 SQL 저장소에 등록 쿼리를 쌓아 놓는다. 그리고 커밋시에 한번에 SQL을 DB에 전달한다.
- 트랜잭션 커밋 직전에만 DB에 SQL을 전달하면 되기 때문에 쓰기지연이 가능하다. 쿼리를 한번에 전달해서 성능을 최적화할 수 있다.

# 엔티티 수정 
스냅샷 : 엔티티를 영속성 컨텍스트에 보관할 때, 최초 상태를 복사해서 저장해 둔다.
변경감지 : 엔티티의 변경사항을 DB에 자동으로 반영한다. 트랜잭션을 커밋하면 엔티티 매니저 내부에서 플러시가 호출된다. 엔티티와 스냅샷을 비교해 변경된 엔티티가 있으면 쓰기 지연 SQL 저장소에 수정 쿼리를 쌓아 놓고 한번에 SQL을 DB에 전달한다.

# 엔티티 삭제 : em.remove(entity)
- 삭제할 엔티티를 우선 조회한다. 그리고 삭제하면 삭제 쿼리를 쓰기 지연 SQL 저장소에 쌓아 놓는다. 그리고 커밋시에 한번에 SQL을 DB에 전달한다.
- 삭제를 요청한 엔티티는 영속성 컨텍스트에서 제거되므로 사용하지 말고 가비지 컬렉션의 대상이 되도록 두는 것이 좋다.

* 플러시 : em.flush()
- 트랜잭션을 커밋하는 순간 영속성 컨텍스트의 변경 내용을 DB에 동기화한다.
- 플러시 실행시 변경감지가 동작해서 영속성 컨텍스트에 있는 모든 엔티티를 스냅샷과 비교해서 수정된 엔티티를 찾아 수정 쿼리를 만들어 쓰기 지연 SQL 저장소에 등록한다. 쓰기 지연 SQL 저장소의 쿼리를 DB에 전달한다. (등록/수정/삭제 쿼리)
- 영속성 컨텍스트를 플러시하는 방법은 다음과 같다.
1) em.flush() 직접 호출 - 테스트 외에 거의 사용하지 않는다.
2) 트랜잭션 커밋시 자동 호출
3) JPQL 쿼리 실행시 자동 호출

* 준영속
- 준영속 상태의 엔티티는 영속성 컨텍스트가 제공하는 기능을 사용할 수 없다.
- 비영속 상태와 흡사하지만 식별자 값은 가지고 있다.
- 영속 상태의 엔티티를 준영속 상태로 만드는 방법은 다음과 같다.
1) em.detach(entity) - 특정 엔티티를 영속성 컨텍스트로부터 분리. 1차 캐시와 쓰기 지연 SQL 저장소에 해당 엔티티를 관리하는 정보 제거한다.
2) em.clear() - 영속성 컨텍스트 초기화. 영속성 컨텍스트의 모든 엔티티를 준영속 상태로 만든다.
3) em.close() - 영속성 컨텍스트를 종료해 모두 준영속 상태가 된다.

* 병합 : em.merge(entity) 
- 파라미터로 넘어온 엔티티의 식별자 값으로 1차 캐시를 조회하고 찾는 엔티티가 없으면 DB에서 조회한다. DB에도 없으면 새로운 엔티티를 생성해 반환한다. 
따라서, 준영속/비영속 상태에 관계없이 영속 상태의 엔티티를 반환하는 insert/update 기능을 수행한다.


참고서적 - 자바 ORM 표준 JPA 프로그래밍 (김영한)
그림으로 이해를 돕는 http://www.slideshare.net/zipkyh/ksug2015-jpa3-jpa

'Development > JPA' 카테고리의 다른 글

엔티티 매핑  (0) 2017.11.12
JPA 시작  (0) 2016.11.20
JPA 소개  (0) 2016.05.04

+ Recent posts