https://docs.spring.io/spring-framework/reference/data-access/orm/hibernate.html

Import javax.persistence.*;

1) 엔티티 매니저 팩토리

EntityManagerFactory emf = Persistence.createEntityManagerFactory("영속성 유닛 이름");

  • 엔티티 매니저를 생성하는 팩토리 클래스
  • persistence unit (영속성 유닛)을 찾아서 엔티티 매니저 팩토리를 생성함.
  • 영속성 설정 정보를 읽으면서 JPA를 동작 시키기 위한 기반 객체를 만듬.
  • JPA 구현체에 따라서 데이터베이스 커넥션 풀도 생성 -> 생성 비용 큼
  • 엔티티 매니저 팩토리는 애플리케이션 전체에서 딱 한번만 생성하고 공유해서 사용함.

2) 엔티티 매니저

EntityManager em = emf.createEntityManager();

  • 엔티티 매니저 팩토리를 통해 엔티티 매니저를 생성
  • JPA 기능 대부분을 제공 (DB에 엔티티의 CRUD 동작)
  • 엔티티 매니저 내부에서 데이터베이스(커넥션)을 유지하면서 DB와 통신
  • 가상의 데이터 베이스
  • 엔티티 매니저는 데이터 베이스 커넥션과 밀접한 관계 때문에 스레드 간에 공유/재사용이 불가능하다.

종료

em.close(); emf.close();
사용을 마친 엔티티 매니저, 팩토리는 모두 종료해야함.


3) 트랜젝션

EntityTransaction tx = EntityManager.getTransaction();

try{
	tx.begin();
    logic(em);
    tx.commit();
}catch (Exception e){
	tx.rollback();
}

트랜젝션을 통한 커밋, 롤백을 통해 DB의 영속성 유지를 가능하게 함.


4) CRUD

  • 등록 - EntityManager.persist();
    • 엔티티의 매핑정보를 통해 SQL을 생성하여 데이터베이스에 전달
  • 수정
    • EntityManager.update(); 가 아니라,
    • JPA는 어떤 엔티티가 변경되었는지 추적하는 기능을 가짐.
    • 해당 엔티티 내의 ID 매핑 정보를 통해 변경된 엔티티를 식별하고 DB에 값을 반영함.
  • 삭제 - EntityManger.remove();
    • 엔티티 삭제요청, DELETE SQL을 생성하여 전달한다.
  • 조회 - EntityManger.find(엔티티.class, 아이디)
    • ex) em.find(Member.class, id)
    • 기본키로 매핑한 식별자 값으로 엔티티를 하나 조회하는 SQL을 생성함.

5) 내부 구조

https://www.javatpoint.com/spring-boot-jpa

  • 엔티티 매니저 팩토리는 여러 스레드가 동시에 접근해도 안전함, 서로 다른 스레드 간에 공유 가능
  • 엔티티 매니저는 여러 스레드가 동시에 접근하면 동시성 문제가 발생하므로 스레드 간 공유 불가능
    엔티티 매니저는 데이터 베이스 연결이 필요한 시점 전까지는 커넥션을 얻지 않음
  • 보통 트랜젝션을 시작할때 커넥션을 얻음

6) 영속성 컨텍스트

엔티티 매니저를 통해 엔티티를 저장/조회 할 시 엔티티 매니저는 영속성 컨텍스트에 해당 엔티티를 보관하고 관리함.

6-1) 엔티티 생명주기

  • 비영속(new/transient): 영속성 컨텍스트에 전혀 관계가 없는 상태

    엔티티 객체를 생성했을 때, 영속성 컨텍스트에 관련되지 않은 상태

  • 영속(managed): 영속성 컨텍스트에 저장된 상태

    엔티티 매니저를 통해서 엔티티를 영속성 컨텍스트에 저장햇을 때,
    영속성 컨텍스트에 의해 관리되는 영속상태
    EntityManager.persist()

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

    영속성 컨텍스트가 관리하던 영속 상태 엔티티가 더이상 관리되지 않으면 준영속 상태
    EntityManager.close() , EntityManager.claer()
    EntityManager.detach(엔티티 객체)

  • 삭제(removed): 삭제된 상태

    엔티티를 영속성 컨텍스트, DB에서 삭제한 상태
    EntityManager.remove(엔티티 객체)

6-2) 구성

영속성 컨텍스트 식별자

  • 영속성 컨텍스트에서 엔티티를 식별하는 방법은 식별자값(@Id 기본키)을 통해서 구분함.
  • 식별자 값이 없는 엔티티는 영속성 컨텍스트를 사용할 시에 예외 발생

DB 액세스

  • 영속성 컨텍스트에 엔티티 저장시, 트랜젝션을 커밋할 때 DB에 새로운 엔티티 정보를 Flush한다.

사용 장점

  • 1차 캐시
  • 동일성 보장
  • 트랜잭션을 지원하는 쓰기 지연
  • 변경 감지
  • 지연 로딩

6-3) 1차 캐시

영속성 컨텍스트 내부에 Key-Value 형태의 맵을 통해 엔티티를 캐싱

컨텍스트 내부 Map

식별자 값 : 엔티티 클래스의 Id를 Key로 식별한다.
Id를 가진 Key가 컨텍스트 내부 캐시에 존재하지 않으면 데이터베이스에 조회해서 데이터를 컨텍스트 내부에 유지한다.

6-4) 엔티티 동일성 보장

영속성 컨텍스트 내부에 존재하는 인스턴스를 EntityManager.find() 를 통해 조회했을 때, 같은 Id로 두 번 참조하여 객체를 저장하면 두 인스턴스 객체는 동일하다. (==)

6-5) 쓰기 지연(Transactional write-behind)

  • 영속성 컨텍스트에 엔티티를 등록할 때, 바로 DB에 저장하지 않고 내부 쿼리 저장소 에 INSERT SQL을 쌓아둠.
  • 트랜젝션 커밋 시에 쌓아둔 쿼리를 데이터 베이스로 보냄.

Flush

  • 트랜젝션 커밋 시 엔티티 매니저는 영속성 컨텍스트를 플러시함.
  • : 영속성 컨텍스트 내부의 변경 내용과 DB를 동기화하여 데이터를 반영함.

6-6) 변경 감지

영속 상태인 엔티티만(영속성 컨텍스트에 의해 관리되는) 변경감지 범위에 해당함

  • 별도의 수정 메서드나 쿼리 없이, 엔티티를 조회하여 해당 엔티티의 필드 값을 변경해주면
  • 엔티티 컨텍스트 내부에 처음 매핑 되었던 Key-Value와 함께있는 스냅샷과 해당 엔티티를 비교함.
  • 여기서 변경된 점을 비교하여 수정 SQL을 DB에 반영해서 커밋
    UPDATE 쿼리에 모든 필드를 반영함. -> UPDATE 문마다 차별화할 필요 없이 모든 필드를 다 쓰는 쿼리문을 반복해서 사용가능.
  • 모든 필드를 UPDATE문에 포함시키지 않으려면 @DynamicUpdate , @DynamicInsert 어노테이션을 사용

6-7) Flush

영속성 컨텍스트의 플러시 3가지 트리거

  • em.flush() 호출
  • 트랜잭션 커밋 시 자동 호출
  • JPQL 쿼리 실행

플러시 모드

  • FlushModeType.AUTO: 커밋이나 쿼리를 실행할 때 플러시(default)
  • FlushModeType.COMMIT: 커밋할 때만 플러시

EntityManager.setFlushMode(FlushModeType.COMMIT)

6-8) 준영속

준영속 상태의 엔티티는 영속성 컨텍스트의 변경감지 범위에 들지 않는다.

  • EntityManager.detach(엔티티 객체) -> 컨텍스트 내부 캐시 맵에서 해당 엔티티 매핑 정보를 제거
  • 해당 엔티티에 대한 SQL 문도 쓰기지연 SQL 저장소에서 사라짐.

지연 로딩 불가능 ( 프록시 객체를 영속성 컨텍스트를 통해 불러오는데, 영속성 컨텍스트에 의해 관리되지 않기 때문)

EntityManager.merge(엔티티 객체) 를 통해서 다시 영속성 컨텍스트에 관리받는 영속상태로 변경가능하다.
return 새로운 영속 상태의 엔티티(새로운 인스턴스)

병합도 EntityManager.persist(엔티티 객체) 처럼 캐시를 조회하고 엔티티 매핑 정보가 없으면 DB에서 조회하거나 새로운 엔티티를 만든다. (save or update)

0개의 댓글