본문 바로가기
JPA/ORM 표준 JPA

03. 영속성

by clearinging 2021. 6. 30.
반응형

EntityManagerFactory 와 EntityManager

  • EntityManagerFactory : EntityManager 객체를 생성하는 클래스 -> 여러 쓰레드가 접속 가능
    • EntityManagerFactory를 생성할 때 Connection Pool도 같이 생성함
  • EntityManager : 실제 트랜젝션 이 작용하는 곳에서 DB에 CRUD 연산을 해주는 객체 -> 여러 쓰레드가 공유하면 동시성 문제 발생
    • EntityManager가 생성되었지만, 실제 물리 DB와 연결할필요가 없으면 Connection Pool을 획득하지 않는다.
    • EntityManager가 생성될 때 영속성 컨택스트를 같이 생성한다.(아래 참고)

영속성 컨택스트(Persistence Context)

정의 : 엔티티 객체를 영구적으로 정장하는 환경

특징

  • 엔티티를 저장하거나, 조회 하게되면 영속성 컨택스트가 엔티티 객체를 저장

생명주기

생명주기

비영속

  • 정의 : 영속성컨택스트와 관련없는 상태를 의미
User user = new User();
user.setId("hello");

영속

  • 정의 : 영속성 컨택스트가 저장한 상태(조회, 저장 후)
  • find, JPQL를 사용해서 Entity객체를 조회하거나, persist를 통해서 객체를 저장한 Entity객체를 영속성 상태라고 말한다.
  • 특징
    • 식별자 값 존재 : @Id 가 붙은 필드 변수에 null이 아닌 값이 무조건 있어야 한다
    • DB저장 시점 : EntityManger를 commit하는 순간 flush 라는 함수가 호출 되는데 그 때 persist된 객체를 DB에 저장하는 query를 날린다.

준영속

  • 정의 : 영속성 컨택스트에 저장되었다가 분리된 상태
  • 엔티티 객체가 영속성 컨택스트에서 불리된 상태(영속성 상태 -> 준영속)
  • 종류
    • em.detach(Entity class) : 특정 Entity만 준영속으로 변경 -> 쓰기 지연SQL, 변경 감지 정보를 전부 파기 한다
    • em.clear() : 영속성 컨택스트를 다시 초기화 해서 모든 영속성이었던 Entity 객체를 준영속으로 변경
    • em.close() : 영속성 컨택스트를 종료 해서 모든 영속성 컨택스트의 정보를 준영속 상태로 변경
  • 특징
    • 비영속에 가까움 : 1차 캐시, 변경 감지, 쓰기 지연 변경 모두 사용 안함
    • 식별자 값이 있음 : 한번 영속 상태였기 때문에 Id는 존재
    • 지연 로딩 불가

삭제

  • 정의 : 삭제된 상태

영속성 컨택스트의 장점 및 특징

  1. 1차 캐시
  • 정의 : 영속성 컨택스트 내부에 존재하는 캐시
  • Map Entity 객체를 으로 관리
  • @Id가 선언된 필드를 Key로 가짐
  • 동일한 트랜젝션에서 동일한 @Id를 가진 Entity 객체를 조회하게 된다면 처음에는 DB에 접근하지만, 두번 째는 1차 캐시에 존재한 객체를 가져온다.
  • 1차 캐시에서 조회했을 때 없으면 DB에서 데이터 조회
  1. 영속 Entity 동일성 보장
  • 동일한 객체를 반환하기 때문
    • 동일성 : 실제 인스턴스 자체가 동일 == 연산결과 true
    • 동등성 : 실제 인스턴스는 다르나 내부 값이 동일(equals 함수로 정의 된 것)
  1. 지연 등록
  • 트랜젝션을 commit하기 전에 까지 database에 엔티티 객체를 EntityManager에 저장만 한다
  • commit이 나오면 insert sql이 합쳐져서 한번에 나가게 한다.
  • 지연 쓰기(Transaction wrtie-behind)
  • Entity 객체를 1차 캐시에 집어 넣고 쓰기 지연 SQL 저장소에 저장
  • commit시 자동으로 flush를 호출
  • 중간에 update query가 존재할 경우 성능 최적화 가능
  1. 변경 감지
  • 비즈니스 로직으로 인해서 다양한 update 쿼리 생성
  • 영속성 컨택스트에 처음에 들어가면 스냅샷에 최초 상태를 복사한다
  • 영속상태의 객체만 적용이 된다
  • 마지막 commit을 날리면 스냅샷이랑 다른 컬럼이 존재하면 모든 column을 한번에 update한다
    • 단점 : 전송량 증가
    • 장점
      • Application에서 수정 쿼리 재사용
      • DB에서도 동일 쿼리가 존재하면 이전에 파싱한 쿼리를 재사용
  • 동적으로 update쿼리 생성
    • hibernate의 update SQL 생성전략인 @org.hibernate.annotations.DynamicUpdate를 사용해야함
@Entity
@org.hibernate.annotations.DynamicUpdate
public class User {
    // ,,, 
}
  1. 지연 삭제
  • commit(flush)가 호출 될 때 마지막에 삭제 sql이 날라가게 된다
  1. 지연 로딩(Lazy Loading)
  • 처음에 참조한 연관 관계 Entity 객체를 DB에서 바로 가져오지 않고 Proxy 객체로 가지고 있다가 Proxy객체를 참조하면 실제 DB에서 데이터를 가져오는 것
  • Trasaction 내부에 존재해야지 가능

Flush

  • 정의 : 영속성 컨택스트의 변경 내용을 DB에 반영
  • flush 를 한 후에도 영속성 컨택스트에 데이터는 남아있고, DB에 쿼리문으로 반영만 한 상태이다.

작동 과정

  1. (변경 감지)스냅샷과 수정된 Entity 를 찾아 수정 쿼리를 SQL저장소에 등록
  2. 쓰기 지연 SQL를 DB에 전송(등록, 수정, 삭제 쿼리)

flush 하는 방법

  1. 함수 직접 호출 : entityManager.flush()
  • 주로 사용하지 않음
  1. 트랙젝션 commit시 자동 호출
  • commit 이 일어 나기전에 flush가 자동으로 호출
  1. JPQL 쿼리 실행 전에 flush 자동 호출
  • criteria와 같은 객체 지향 쿼리를 호출할 때 플러시가 자동을 호출
  • JPQL 호출 이전에 영속성 컨택스트에 존재하는 객체를 JPQL에서 조회할 수 있기 때문에 JPQL 호출 이전에 flush하고 다음에 JPQL을 호출 한다

병합(Merge)

  • 정의 : 준영속 객체를 다시 영속성 객체로 변경하는 작업(준영속 객체를 새로운 영속성 객체로 반환해 주는 것)

실행 순서

  1. merge 호출
  2. 1차 캐시를 통해서 Entity객체 존재 여부 판단 -> 없으면 DB에서 조회해서 1차 캐시로 저장
  3. 새로 조회한 영속 Entity 객체에 merge에서 받아온 데이터를 하나씩 차례대로 넣어준다 -> 변경 감지 반영
  4. 새로 영속성 컨택스트에 존재하는 Entity객체를 반환
반응형

'JPA > ORM 표준 JPA' 카테고리의 다른 글

06 연관관계 Mapping 종류  (2) 2021.08.21
05 연관관계  (0) 2021.07.28
04 Entity  (3) 2021.07.08
02. JPA 요소들  (2) 2021.06.29
01. JPA 소개  (0) 2021.05.19