JPA-영속성

Sungjin·2021년 7월 2일
0

JPA

목록 보기
3/10
post-thumbnail

영속성 컨텍스트

JPA에서 객체와 관계형 데이터베이스의 매핑 뿐 아니라 가장 중요한 요소 중 하나
엔티티를 영구 저장하는 환경

  • 사용 방법

    1. Client의 요청
    2. Entity Manager Factory 에서 Client에게 EntityManager 생성
    3. EntityManager를 이용하여 영속성 컨텍스트 접근
    4. 영속성 컨텍스트에서 DB접근
  • 사용 환경

    • J2SE 환경
      • Entity Manager와 영속성 컨텍스트가 1:1 매칭
    • J2EE, 스프링 프레임워크 환경
      • Entity Manager와 영속성 컨텍스트가 N:1 매칭 즉, 여러 요청에 대하여 처리 가능
  • 엔티티의 생명주기

    • 비영속
      영속성 컨텍스트와 관련 없는 상태

       Book book=new Book();

      위의 코드 처럼 아무런 처리과정 없이 자바에서 객체만 생성한 형태를 비영속이라 함

    • 영속
      영속성 컨텍스트에 관리되는 상태

      //객체 생성(비영속)
      Book book=new Book();
      
      // Entitty Manager Factory 생성
      EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
      
      //EntityManager 생성
      EntityManager em = emf.createEntityManager();
      
      //Transaction 생성
      EntityTransaction tx = em.getTransaction();
      
      tx.begin();
      //객체를 저장(영속)
      em.persist(book);	

      위의 코드 처럼 생성된 객체를 EntityManager에 저장한 상태를 영속상태라고 함

    • 준영속
      영속성 컨텍스트에 저장되었다가 분리된 상태
      영속성 컨텍스트가 제공하는 기능 사용 못함

      em.detach(book);
      
      //영속성 컨텍스트를 완전히 초기롸
      em.clear();
      
      //영속성 컨텍스트를 종료
      em.close();
    • 삭제
      영속성 컨텍스트에서 삭제된 상태

      em.remove(book);

영속성 컨텍스트의 이점

  • 1차 캐시
    Entity Manager에 객체를 persist를 시키면 바로 DB에 저장되는 것이 아닌 Trasaction Commit시점에 DB에 Insert문이 실행됨. 즉, Transaction이 Commit전이라면 영속성 컨텍스트 1차 캐시에 저장됨.
    1차캐시에 원하는 객체가 없을 경우 데이터 베이스에서 조회.즉,
    1. Entity Manager 에 find 요청
    2. 1차 캐시에 객체가 있는지 확인.
      • 없다면?
        2-1. DB조회
        2-2. 조회된 객체를 1차 캐시에 저장
    3. 객체를 반환
//객체 생성(비영속)
Book book=new Book();
book.setId("1");

// Entitty Manager Factory 생성
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");

//EntityManager 생성
EntityManager em = emf.createEntityManager();

//Transaction 생성
EntityTransaction tx = em.getTransaction();

tx.begin();
//객체를 저장(영속) , 1차 캐시에 저장
em.persist(book);	

// 1차 캐시에서 조회
Book findBook=em.find(Book.class,"1");

// DB에서 조회
Book findBook=em.find(Book.class,"2");

위의 코드 처럼 객체의 아이디가 "1"로 정해진 객체는 현재 Transaction이 Commit 되지 않은 시점에서 Persist되었기 때문에 아직 1차 캐시에 있음. 아이디가 "2"로 정해진 객체는 1차 캐시에 없기 때문에 DB에서 조회하게 됨.

  • 동일성 보장
//DB에서 조회
Book a=em.find(Book.class,"1");
//1차 캐시에서 조회
Book b=em.find(Book.class,"1");

a==b; //True

영속성 컨텍스트는 1차 캐시를 이용한다고 하였습니다. 위의 코드에서 a의 경우 일단 영속성 컨텍스트의 1차 캐시에 존재하지 않으므로 DB에서 조회되며 조회된 객체는 1차 캐시에 저장됩니다. b의 경우는 1차 캐시에 아이디 "1"을 가진 객체가 존재하므로 1차 캐시에서 조회하게 됩니다. 따라서 a와 b는 동일한 객체를 조회하도록 됩니다!

  • 트랜잭션을 지원하는 쓰기 지연
    1차 캐시에서 설명했듯이 Transaction이 commit되기 전에는 DB에 Insert문을 날리지 않고 Commit하는 순간 Insert문을 날리게 됩니다.
//객체 생성(비영속)
Book book1=new Book();
book.setId("1");

Book book2=new Book();
book.setId("2");

// Entitty Manager Factory 생성
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");

//EntityManager 생성
EntityManager em = emf.createEntityManager();

//Transaction 생성
EntityTransaction tx = em.getTransaction();

tx.begin();
//객체를 저장(영속) , 1차 캐시에 저장
em.persist(book1);	
em.persist(book2);
//아직 DB에 Insert 문을 보내지 않음

tx.commit();
//커밋하는 순간 Insert문을 한번에 보냄

위의 코드는 그 예를 보여 주고 있습니다!

  • 변경 감지
    1. 엔티티 조회
    2. 엔티티와 스냅샷 비교
    • 변경 데이터가 있다면
      2-1. 영속성 컨텍스트 내에 쓰기 지연 SQL저장소에 UPDATE 문 생성
    1. flush (Commit전 실행. 실질적으로 이 부분에서 SQL이 DB에 전송됨)
    2. commit
// Entitty Manager Factory 생성
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");

//EntityManager 생성
EntityManager em = emf.createEntityManager();

//Transaction 생성
EntityTransaction tx = em.getTransaction();

tx.begin();
//객체를 조회
Book book=em.find(Book.class,"1);

book.setName("Nice");

//조회된 엔티티 수정??? 또 다른 처리 과정이 필요하지 않을까!

tx.commit();
//커밋하는 순간 Insert문을 한번에 보냄

위의 코드는 영속성 컨텍스트에 조회된 객체에서 객체의 데이터를 수정하고 있습니다. 여기서 의문이 들죠.. '객체가 변경되었으니 영속을 또 시켜야하나?? 아니면 update라는 code를 새로 만들어야 하나??' 그럴 필요 없이 Entity Manager는 객체의 스냅샷을 남겨 Trasaction이 commit하기 전에 스냅샷과 객체를 비교하게 되어 변경된 부분이 있으면 commit 시점에 update문을 날리게 됩니다.

Flush
영속성 컨텍스트의 변경내용을 DB에 반영

  • 발생 시점
    • em.flush() 직접 호출
    • Transaction Commit시 자동 호출
    • JPQL 쿼리 실행시 자동 호출
  • 플러시 모드 옵션
    em.setFlushMode(FlushModeType.COMMIT)
    • FlushModeType.AUTO : default
    • FlushModeType.COMMIT : Commit할때만 Flush
  • 지연 로딩
    내용이 많으므로 나중에 한번에 정리하겠습니다 :)

이상으로 포스팅을 마치겠습니다. 감사합니다 :)

이 글은 인프런 김영한님의 '자바 ORM 표준 JPA 프로그래밍 - 기본편'을 수강하고 작성합니다.
출처:https://www.inflearn.com/course/ORM-JPA-Basic

profile
WEB STUDY & etc.. HELLO!

0개의 댓글