[자바 JPA 표준] 영속성 컨텍스 - 영속성 컨텍스트 속성

sonnng·2023년 9월 16일
0

Spring

목록 보기
9/41
  • 엔티티 매니저 팩토리와 엔티티 매니저

    • 엔티티 메니저 팩토리에서 고객의 요청이 오면 EntityManager를 각각 생성하고, 엔티티 매니저가 db 커넥션을 사용하게 된다.
  • 영속성 컨텍스트(JPA를 이해하는데 가장 중요 용어)

    • '엔티티를 영구 저장하는 환경'이라는 뜻을 가진다.

    • EntityManager.persist(entity) : 영속성 컨텍스트를 통해 해당 엔티티를 영속화한다. 영속성 컨텍스트에 저장한다는 의미다.

    • 엔티티 매니저를 통해 영속성 컨텍스트에 접근한다.

      • J2SE환경에서는 엔티티 매니저와 영속성 컨텍스트가 1:1 매핑된다.
    • 엔티티 생명주기

      • 비영속 : 영속성 컨텍스트와 관계없는 새로운 상태
      • 영속 : 영속성 컨텍스트에 관리되는 상태(em.persist(entity))
      • 준영속
      • 삭제 : 삭제된 상태
    • 비영속 상태란?

      • 객체는 따로 생성해놓고 JPA와 전혀 관계가 없는 상태다.
        //비영속(엔티티를 생성한 상태)
         Member member = new Member();
         member.setId(1L);
         member.setName("helloA");
    • 영속 상태란?

      • 엔티티 매니저를 얻어와서 em.persist(entity)를 하게 되면 영속 컨텍스트에 객체가 영속상태가 된다.
        //엔티티를 영속
         Member member = new Member();
         member.setId(1L);
         member.setName("helloA");
         em.persist(member);
      • 트랜잭션 커밋이 되면 그 때 바로 영속상태가 된다.
      • 영속 컨텍스트에 1차 캐시에 @Id, Entity 쌍에 저장한다.
    • 영속성 컨텍스트 이점? 애플리케이션-db 사이에 위치한다.

      • 1차 캐시

        • 1차 캐시에서 조회해보고 없다면 db를 조회해서 1차 캐시에 저장하고 반환한다.

        • 고객 요청을 응답하는 과정에서 데이터베이스 하나의 트랜잭션 안에서만 사용되고 반환되므로 크게 이점은 아니다.

          EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello"); // "hello"는 Persistence Unit의 이름과 일치해야 합니다.
          
          EntityManager em = emf.createEntityManager();
          EntityTransaction tx = em.getTransaction();
          tx.begin(); //트랜잭션 시작
          
          try{
             //code 작성
              //비영속
           Member member = new Member();
            member.setId(101L);
            member.setName("helloA");
          
          em.persist(member);
          //findMember.setName("HelloJPA");
          // JPA를 통해 엔티티를 가져오면, 엔티티 변경이 감지되면 커밋되기 직전에 update 쿼리가 나간다.
          
          System.out.println("Member 101 : "+em.find(Member.class, 101L));
          System.out.println("Member 101 : "+em.find(Member.class, 101L));
          
          tx.commit();
          
          }catch(Exception e){
              tx.rollback();
          }finally {
              em.close();
          }
          
          emf.close();

          -> select 문이 하나만 나가는 이유 : 1차 캐시에 저장된다.

      • 동일성 보장

        Member member = em.find(Member.class, 101L);
        Member member1 = em.find(Member.class, 101L);
        
        System.out.println(member == member1); //true
      • 트랜잭션을 지원하는 쓰기 지연

        • INSERT SQL을 DB에 보내지 않는다. em.persist 가 계속 적혀있어도 커밋하는 순간 한번에 트랜잭션이 일어난다.
        • INSERT SQL 생성 -> 쓰기지연 SQL 저장소에 저장, 2차 캐시에 저장
        • INSERT SQL 생성 -> 쓰기 지연 SQL 저장소에 저장, 1차 캐시에 저장
        • 트랜잭션 커밋 -> DB에 저장
      • 변경 감지(엔티티 수정)

           EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello"); // "hello"는 Persistence Unit의 이름과 일치해야 합니다.
        
            EntityManager em = emf.createEntityManager();
            EntityTransaction tx = em.getTransaction();
            tx.begin(); //트랜잭션 시작
        
            try{
           // Member member1 = new Member(150L, "A");
           // Member member2 = new Member(160L, "A");
        
           // em.persist(member1);
           // em.persist(member2);
        
            Member member = em.find(Member.class, 150L);
            member.setName("zzzz");
        
            //이 코드는 써서는 안된다. em.persist(member); setter를 통해서 update query가 나간다.
        
            System.out.println("=================="); // persist insert query보다 먼저 출력된다.
        
            tx.commit(); //트랜잭션 커밋
        
            }catch(Exception e){
                tx.rollback();
            }finally {
                em.close();
            }
        
            emf.close();
        
        • 객체를 수정했을때 왜 em.persist를 하지 않아도 되는가?

            1. 커밋하면 flush() 발생..
            1. 엔티티와 스냅샷(값을 딱 읽어온 시점, 영속 컨텍스트에 들어온 시점의 값) 비교

              ..다르다면 UPDATE SQL 로 DB에 반영
          • 따라서 JPA에서는 값이 바뀌면 영속 컨텍스트 내에 스냅샷과 비교해서 변경 감지.. UPDATE Query를 DB에 보내고 트랜잭션 커밋을 수행한다.

      • 플러시(영속성 컨텍스트의 변경내용을 DB에 반영)

        • 더티채킹(변경 감지) - 수정 엔티티 쓰기 지연 SQL 저장소에 등록 - 쓰기 지연 SQL 저장소 쿼리를 DB에 전송(등록, 수정, 삭제 쿼리)
        • 변경사항을 반영하는 과정이라고 생각하면 편하다.
        • JPQL 쿼리 실행시 직전에 플러시를 실행해서 에러가 발생하지 않도록 Default로 저장되어 있다.
        • 플러시 모드 옵션
          • FlushMode.AUTO : 커밋/쿼리 실행시 플러시(기본값)
          • FlushMode.COMMIT
        • 영속성 컨텍스트를 비우지 않는다.
        • 영속성 컨텍스트의 변경내용을 데이터베이스에 동기화
        • 트랜잭션이라는 작업 단위가 중요 -> 커밋 직전에만 동기화 하면 된다.
    • 준영속 상태

      • 영속 상태의 엔티티가 영속성 컨텍스트에서 분리되었을 때의 상태이다.
      • 이 상태로 만드는 방법 : em.detach(member), em.clear()
    

0개의 댓글