JPA API 이해

김주언·2022년 10월 26일
0

Spring Boot

목록 보기
7/8

JPA API 이해

JPA를 사용하여 CRUD 프로그램을 구현하는데 사용되는 API들과 엔티티의 상태 및 라이프 사이클


EntityManagerFactory와 EntityManager

JPA가 EntityManager 객체를 얻기까지의 과정

  1. Persistence 클래스를 이용하여 영속성 유닛 정보가 저장된 JPA 메인 환경설정 파일(persistence.xml)을 로딩
  2. 영속성 유닛 설정 정보를 바탕으로 EntityManagerFactory 객체 생성
  3. EntityManagerFactory로부터 EntityManager 얻어서 데이터베이스 연동 처리

EntityManager를 얻은 후에는, 이 객체를 이용하여 CRUD 작업을 진행하면 된다. 다만 주의할 점은 등록, 수정, 삭제 작업은 반드시 트랜잭션 내에서 끝내주는 것

EntityManager가 제공하는 CRUD 기능의 메소드

메소드기능
persist(Object Entity)엔티티 영속화 insert
merge(Object Entity)준영속 상태의 엔티티 영속화 update
remove(Object Entity)영속 상태의 엔티티 제거 delete
find(Class entityClass, Object pk)하나의 엔티티 검색 select one
createQuery(String jpql, Class resultClass)JPQL에 해당하는 엔티티 목록 검색 select list



영속성 컨텍스트와 엔티티 상태

영속성 컨텍스트 Persistence Context

영속성 컨텍스트

  • 논리적인 개념으로서 EntityManager 생성 시 자동으로 생성됨.
  • 엔티티 객체들을 관리하는 일종의 컨테이너, EntityManager가 제공하는 메소드를 통해 관리한다.
  • EntityManager를 통해 접근 가능

EntityManager = 영속성 컨텍스트라고 생각하면 됨

엔티티 상태

영속성 컨텍스트에 등록된 엔티티가 가지는 상태는 아래와 같다

  • 비영속
    • New
    • 엔티티가 영속성 컨텍스트와 무관한 상태
    • 엔티티 객체의 생성만 된 상태, 아직 엔티티가 영속성 컨텍스트에 저장된 것은 아님
  • 영속
    • Managed
    • 영속성 컨텍스트에 저장된 상태
    • persist(), find()
  • 준영속
    • Detached
    • 엔티티가 영속성 컨텍스트에 한번 저장됐다가 분리된 상태
    • 영속성 컨텍스트에서 벗어났기 때문에 해당 상태의 엔티티는 값을 수정해도 데이터베이스에 영향 x
    • detach(), clear(), close()
    • merge() 메소드를 통해 다시 영속 상태로 전환 가능
  • 삭제
    • Removed
    • remove()



영속성 컨텍스트와 1차 캐시

영속성 컨텍스트는 내부에 1차 캐시를 가지고 있다. 1차 캐시는 일종의 Map과 같은 컬렉션으로 Key와 Value로 엔티티를 관리한다.
이 때 Key 값은 @Id로 매핑한 식별자 값이고 Value값은 엔티티 객체가 된다.

  1. EntityManager의 persist() 를 통한 엔티티 영속화
  2. 엔티티는 영속성 컨텍스트의 1차 캐시에 등록됨 (@Id : 엔티티 객체)

이 때 중요한 점은 1차 캐시에 저장된 엔티티는 바로 실제 데이터베이스에 반영되지 않고, EntityTransaction의 commit()으로 트랜잭션을 종료할 때 실제로 반영된다는 것

이렇게 영속성 컨텍스트에 저장된 엔티티를 데이터베이스에 반영하는 과정을 Flush라고 한다.


영속성 컨텍스트와 SQL 저장소

엔티티 저장

영속성 컨텍스트는 내부에 1차 캐시뿐만 아니라 SQL 저장소도 가진다

영속성 컨텍스트에 엔티티를 persist() 하여 저장하면 영속성 컨텍스트는 두 가지 작업을 순차적으로 처리한다.

  1. 엔티티를 1차 캐시에 저장
  2. 1차 캐시에 저장된 엔티티에 해당하는 INSERT 구문 생성하여 SQL 저장소에 등록

이렇게 계속 새로운 엔티티를 누적하다가 commit()메소드를 통해 트랜잭션을 종료하면 SQL 저장소에 저장했던 모든 SQL을 한번에 데이터 베이스로 전달한다.

→ 성능 최적화

엔티티 수정과 스냅샷

엔티티를 검색한 후, 검색된 엔티티를 수정한다고 가정한다.

      EntityManagerFactory emf = Persistence.createEntityManagerFactory("ex01");
      EntityManager em = emf.createEntityManager();
      EntityTransaction tx = em.getTransaction();

      tx.begin();

      Board board = em.find(Board.class, 1L);
      board.setTitle("Changed Title");

      tx.commit();
  1. 검색된 엔티티는 영속성 컨텍스트의 1차 캐시에 저장된다
  2. 엔티티 변수 값 수정 시 JPA는 UPDATE 구문을 작성하여 SQL 저장소에 저장
  3. 트랜잭션 종료 시 실질적으로 UPDATE 수행

스냅샷

JPA는 검색된 엔티티를 영속성 컨텍스트에 저장 시, 엔티티의 복사본을 만들어서 별도의 컬렉션에 저장하는데 이 저장공간을 스냅샷이라고 한다.

트랜잭션이 종료될 때 스냅샷에 저장된 원래의 엔티티와 1차 캐시에 수정된 엔티티를 비교하여서 UPDATE 작성하여 이를 SQL 저장소에 저장된 다른 SQL들과 함께 전송한다.


엔티티 삭제

remove() 메소드로 엔티티 삭제 시

  1. 영속성 컨텍스트에서 해당 엔티티가 빠진다.
  2. DELETE 구문이 SQL 저장소에 등록된다.
  3. 트랜잭션 종료 시 SQL 저장소에 등록된 DELETE가 데이터베이스로 전달된다.

목록 검색과 JPQL

테이블에 저장된 특정 데이터의 상세 조회 → find()
목록 조회 → JPQL(Java Persistence Query Language) 이라는 JPA에서 제공하는 별도의 쿼리 명령어 사용

        EntityManagerFactory emf = Persistence.createEntityManagerFactory("ex01");
        EntityManager em = emf.createEntityManager();
        EntityTransaction tx = em.getTransaction();

        tx.begin();

        String jpql = "SELECT b FROM Board b order by b.seq desc";
        List<Board> list =
                em.createQuery(jpql, Board.class).getResultList();

        for(Board board : list) {
            System.out.println(board.toString());
        }

JPQL의 검색대상은 테이블이 아니라 엔티티이다

검색대상이 엔티티이기 때문에 엔티티 이름과 엔티티가 가지고 있는 변수를 사용하여 쿼리를 구성해야한다.

profile
학생 점심을 좀 차리시길 바랍니다

0개의 댓글