티스토리 뷰

JPA

[JPA] 영속성 컨텍스트 이해 및 정리

개발도 운동만큼 2023. 4. 3. 00:37
반응형

JPA를 사용하면서 영속성 컨텍스트에 대해 이해하지 못하면 항상 예기치 못한 사이드 이펙트를 만나곤 한다. 그래서 영속성 컨텍스트에 대해 공부하면서 간단히 정리해본 글이다.

클래스 수준 아키텍처

  • 아래의 이미지는 JPA의 클래스 레벨 아키텍처 입니다. 여러가지 코어적인 JPA의 클래스와 인터페이스를 볼 수 있습니다.

    이미지

  • EntityManagerFactory - EntityManager 클래스의 팩토리 클래스입니다. 이 클래스로 EntityManager 클래스의 인스턴스를 생성하고 관리

  • EntityManager - 인터페이스 입니다. 객체에 대한 영속성 관리작업을 합니다. Query 인스턴스를 생성하는 팩토리 처럼 작동합니다.

  • Entity - 영속 객체입니다. 이 객체의 스펙에 의해서 데이터베이스에 기록될 객체입니다.

  • EntityTransaction - EntityManager와 일대일 관계입니다. 각각의 EntityManager들의 작업은 EntityTransaction 클래스에 의해서 유지된다.

  • Persistence - 이 클래스는 EntityManagerFactory 인스턴스를 생성하는 정적 메소드를 가지고 있다.

  • Query - 인터페이스로서 각각의 JPA 벤더에 의해 구현되며 각 기준에 충족하는 관계형 객체를 얻습니다.

EntityManagerFactory와 EntityManager

이미지

이미지

  • EntityManagerFactory는 하나만 생성해서 애플리케이션 전체에서 공유한다.

    • 애플리케이션 로딩 시점에 딱 하나(DB당 하나)
  • EntityManager는 쓰레드간에 공유하면 안된다.(사용하고 버려야 한다).

    • 클라이언트 요청 마다 하나
    • DB 트랜잭션 단위로 생성하고 제거한다.
  • JPA의 모든 데이터 변경은 트랜잭션 안에서 실행해야 한다.

  • EntityManager를 통해서 영속성 컨텍스트에 접근한다.

    EntityManager와 영속성 컨텍스트

    이미지

    스프링 프레임워크와 같은 컨테이너 환경에서 N:1 관계를 가진다.

영속성 컨텍스트

  • 영속성 컨텍스트(Persistence Context)란

    • Entity를 관리하고 영속화(영구 저장) 시키는 환경

      • ex) EntityManager.persist(entity) : DB가 아닌 영속성 컨텍스트에 저장한다는 의미
    • 논리적인 개념이므로 눈에 보이지 않는다.

      • EntityManager를 통해서 접근하기 때문
    • 애플리케이션과 DB사이에서 엔티티를 관리해주는 환경

  • 영속

    이미지

           //객체를 생성한 상태(비영속)
           Order order = new Order();
           order.setName("떡볶이");
           order.setId(1L);
    
           EntityManager em = emf.createEntityManager();
           em.getTransaction().begin();
    
           //객체를 저장한 상태(영속)
           em.persist(order);
    • 영속은 영속성 컨텍스트에서 관리하는 상태를 말한다.

1차 캐시 와 쓰기 지연 SQL

1차 캐시

        Order order = new Order();
        order.setId(1L);
        order.setName("떡볶이);

        //1차 캐시에 저장됨
        em.persist(member);

        //1차 캐시에서 조회
        Order findOrder = em.find(Order.Class, 1L);
        // DB에서 조회(영속성 컨텍스트에 존재하지 않으면)
        Order findOrder = em.find(Order.class, 2L);
  • JPA를 통해 find를 호출하면 다음과 같은 순서로 동작한다.

    • 1차 캐시에서 조회
    • DB에서 조회(1차 캐시에 없다면)
  • DB로 부터 데이터를 가져오면 1차 캐싱에 저장해두고 동일 트랜잭션 안에서 컬렉션처럼 동작한다.

    이미지

    1차 캐시에서 조회

    이미지

DB에서 조회

EntityManager는 트랜잭션 단위로 생성하고 제거한다. 즉 클라이언트의 요청당 하나의 EntityManager를 생성하고 지운다.

모든 클라이언트가 엔티티를 공유하도록 캐싱하는 것이 아니라, 한 요청에 대한 트랜잭션 안에서만 캐싱을 하는 것.

영속성 컨텍스트가 종료되기 전 까지는 엔티티가 영속성 컨텍스트에 남아있는다.(1차 캐시 사용 가능)

트랜잭션을 지원하는 쓰기 지연

      EntityManager em = emf.createEntityManager();
      EntityTransaction transaction = em.getTransaction(); //엔티티 매니저는 데이터 변경시 트랙잭션을 시작해야 한다.

      transaction.begin(); // 트랜잭션 시작

      em.persist(orderA);
      em.persist(orderB);
      //여기 까지 INSERT SQL을 DB에 보내지 않는다.

      //커밋하는 순간 DB에 INSERT SQL을 보낸다.
      transaction.commit();
      //커밋

이미지

flush 할때 JDBC의 Batch 기능을 이용하여 한번에 쿼리를 날린다.

더티 체킹

변경 감지(엔티티 수정시 이를 체킹하여 영속적으로 수정하도록 하는 기능), 별도의 UPDATE 쿼리가 필요 없음

      EntityManager em = emf.createEntityManager();
      EntityTransaction transaction = em.getTransaction();
      transaction.begin(); // 트랜잭션 시작

      //영속 엔티티 조회
       Order order = em.find(Order.class, 1L);

       //엔티티 데이터 수정
       order.setName("장춘동 족발");
       order.setPrice("20000");

       transaction.commit(); // 커밋

이미지

  • 변경을 감지하는 원리

    • 영속 컨텍스트에서 DB로부터 데이터를 가져올 때 1차 캐시 안에 스냅샷을 찍어둔다.

    • 그리고 추후에 트랙잭션 커밋되는 시점에 엔티티와 스냅샷을 비교한다.

    • 비교하여 변경을 감지하여 UPDATE 쿼리를 생성하여 쓰기 지연 SQL 저장소에 저장한다.

  • 스냅샷이란?

    • 영속성 컨텍스트에 들어온 최초의 값을 기록 (DB로부터든(find)비영속으로 부터든(persist))

JPA의 목적이 컬렉션 다루듯 객체를 다루는 것

반응형
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함