JPA 는 영속성 컨텍스트를 통해서 객체와 DB 사이의 entity 를 관리한다. 영속성 컨텍스트는 entity manager 에 의해 관리되는데, 이를 통해서 애플리케이션과 데이터베이스 사이에서 데이터가 처리된다.
- EntityManagerFactory
애플리케이션 로딩 시전에 DB 당 하나만 생성되는 팩토리이다.
요청이 있을 때마다 EntityManager 를 생성한다.
- EntityManager
영속성 컨텍스트를 관리하는 객체이다.
실제 transaction 단위를 수행할 때마다 생성하는데, DB Connection 을 통해서 DB 에 접근한다.
1. 영속성 컨텍스트 (Persistence Context)
영속성 컨텍스트는 엔티티를 영구 저장하는 환경이다. 애플리케이션과 데이터베이스 사이에서 엔티티 데이터를 저장하고 있는 공간이다. 논리적인 개념으로 JPA 에서 데이터를 저장하면 데이터베이스에 바로 저장되는 것이 아니라 영속성 컨텍스트에 먼저 저장된다.
영속성 생명주기
1) 비영속 (new / transient)
객체를 생성만 하고 아직 영속성 컨텍스트로 관리하고 있지 않는 상태
2) 영속 (managed)
생성된 객체가 영속성 컨텍스트에서 관리되고 있는 상태
바로 DB 에 반영되지는 않는다. commit 이 실행되어야 DB 에 반영된다.
3) 준영속 (detached)
영속성 컨텍스트에 저장되었다가 분리된 상태.
영속성 컨텍스트에서 더이상 관리하지 않아서 영속성 컨텍스트의 기능들을 사용할 수 없다.
- entityManager.detach(entity): 특정 엔티티만 준영속 상태로 전환
- entityManager.clear(): 영속성 컨텍스트를 완전히 초기화
- entityManager.close(): 영속성 컨텍스트를 종료
4) 삭제 (removed)
삭제된 상태. DB 에 삭제를 요청하는 상태.
// 비영속 상태
Entity entity = new Entity();
// Entity Manager 생성
EntityManager entityManager = entityManagerFactory.createEntityManager();
// transaction 시작
EntityTransaction tx = entityManger.getTransaction();
tx.begin();
// 영속 상태
entityManger.persist(entity);
// 준영속 상태
entityManger.detach(entity);
// 삭제 상태
entityManger.remove(entity);
// transaction commit
tx.commit();
2. 영속성 컨텍스트의 특징
1차 캐시와 DB 조회
1) 1차 캐시
영속성 컨텍스트 내부에는 캐시가 존재하는데, 이를 1차 캐시라고 한다.
영속 상태의 엔티티가 1차 캐시에 저장된다. 1차 캐시의 키는 식별자 값 (DB 의 기본키, @Id) 이고 값은 엔티티 인스턴스이다.
2) 조회 프로세스
1. 조회 기능을 수행하면 우선 1차 캐시를 먼저 조회한다.
2. 1차 캐시에 해당 엔티티가 있는 경우 이를 반환한다.
3. 1차 캐시에 없는 경우 데이터베이스에서 해당 엔티티를 조회하여 가져온다.
4. 조회한 데이터를 엔티티로 생성하여 1차 캐시에 저장한다. 이때 엔티티 상태는 영속 상태이다.
5. 해당 엔티티를 조회의 결과로 반환한다.
3) 특징
EntityManager 는 보통 transaction 단위로 생성하고 삭제하기 때문에 메모리에서 데이터를 가져오더라도 큰 장점은 없다.
다만 비즈니스 로직이 복잡해진다면 데이터 조회 성능에 장점을 가질 수 있다.
동일성 보장
영속 Entity 의 동일성을 보장한다.
- 1차 캐시로 반복 가능한 읽기 등급의 트랜잭션 격리 수준을 데이터베이스가 아닌 애플리케이션 차원에서 제공
- 한 em 에서 같은 entity, 데이터에 대해서는 해당 데이터를 참조하는 변수들이 달라도 모두 같은 entity 로 인식한다.
영속 상태의 entity 를 참조하고 있는 두 변수에 대해서 '==' 을 사용한 비교에 true 가 보장된다.
엔티티 등록 - 트랙잭션 쓰기 지연 (transactional write-behind)
- EntityManager 에서 수행된 쿼리들은 쓰기지연 SQL 저장소에 저장된다.
- 엔티티를 생성하는 경우 INSERT 문이 작성되어 SQL 저장소에 저장된다.
- transaction 이 commit 되는 순간에 flush 되어서 DB 에 반영되어 데이터를 생성한다.
엔티티 수정 - 변경감지 (dirty checking)
엔티티를 수정하고 따로 update 에 대한 메서드를 호출하지 않아도 commit 시에 엔티티의 변경사항이 DB 에 반영된다.
1. 1차 캐시: @Id, Entity, Snapshot (값을 읽어온 최초의 상태)
2. JPA 는 커밋하는 시점에 내부적으로 flush() 를 호출하는데, 이때 1차 캐시의 entity 와 snapshot 과 비교한다.
3. 차이점이 있는 경우 JPA 는 UPDATE 쿼리를 작성하여 쓰기지연 SQL 저장소에 저장한다.
4. UPDATE 쿼리를 DB에 반영한 후 commit 한다.
엔티티 삭제
Entity 수정 매커니즘과 동일하다. UPDATE 쿼리가 아닌 DELETE 쿼리가 작성된다.
플러시 (flush)
영속성 컨텍스트의 변경 내용을 DB 에 반영하는 작업이다. (영속성 컨텍스트와 DB 동기화 작업)
transaction commit 이 일어날 때 flush 가 동작하는데, 이때 쓰기지연 SQL 저장소의 쿼리들이 DB 에 전달된다.
플러시 수행 방법
- em.flush(): 플러시 직접 호출
- transaction commit: 플러시 자동 호출
- JPQL 쿼리 실행: 플러시 자동 호출
'Tech > JPA' 카테고리의 다른 글
[JPA] 프록시와 지연로딩 (0) | 2022.05.23 |
---|---|
[JPA] 상속관계 매핑 (0) | 2022.05.23 |
[JPA] 연관관계 매핑 종류 (0) | 2022.05.17 |
[JPA] 연관관계 매핑 (2) - 양방향 연관관계 (0) | 2022.05.11 |
[JPA] 연관관계 매핑 (1) - 단방향 연관관계 (0) | 2022.05.09 |