220922_TIL :자바 ORM 표준 JPA 프로그래밍 - 기본편

백승한·2022년 9월 22일
0

스프링

목록 보기
7/14

영속성 컨텍스트

실제 JPA가 내부에서 어떻게 동작하는지 이해할 수 있다.
• JPA를 이해하는데 가장 중요한 용어
“엔티티를 영구 저장하는 환경”이라는 뜻
• EntityManager.persist(entity)

persist() 메서드는 DB에 저장한다는게 아니라 영속성 컨텍스트 라는 곳에 저장하는 것.

EntityMangerFactory는 고객의 요청이 올때마다 EntityManger를 생성한다.
EntityManger는 내부적으로 커넥션 풀을 사용해서 DB를 사용하게된다.

  • 엔티티 매니저를 통해서 영속성 컨텍스트에 접근
    EM를 생성을 하면 그 안에 1:1로 영속성 컨텍스트(PersistenceContext)가 생성이 된다.
    ** 영속성 컨텍스트(PersistenceContext) - 눈에 보이지 않는 어떠한 공간

영속성 컨텍스트의 이점

1차 캐시

  • 엔티티 조회, 1차 캐시

    1차 캐시는 Map 구조이다.
Member findMember = em.find(Member.class, "member1");

Member findMember2 = em.find(Member.class, "member2");

무조건 DB에서 찾는게 아니라 우선적으로 1차 캐시에서 'member1'를 찾는다. 있으면 캐시에 있는 값을 조회해서 주고 없으면 DB에서 조회해서 1차 캐시에 저장하고 그리고 반환해서 준다.

트랜잭션 안에서만 이루어지는 1차 캐시는 큰 성능의 이점은 없다. 찰나에 순간이기 때문에.

동일성(identity) 보장

Member a = em.find(Member.class, "member1");
Member b = em.find(Member.class, "member1");
System.out.println(a == b); //동일성 비교 true

1차 캐시로 반복 가능한 읽기(REPEATABLE READ) 등급의 트랜잭션 격리 수준을
데이터베이스가 아닌 애플리케이션 차원에서 제공

트랜잭션을 지원하는 쓰기 지연(transactional write-behind)

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

transaction.begin(); // [트랜잭션] 시작
em.persist(memberA);
em.persist(memberB);
//여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.

//커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
transaction.commit(); // [트랜잭션] 커밋

JPA는 쭉 쌓아놓다가 commit하는 순간에 SQL을 날린다.

변경 감지(Dirty Checking)

JPA의 목적은 Java의 Collection을 다루듯이 다룰수 있게 하는 것이다.
예를 들어 List 에서 객체를 꺼내서 데이터를 변경했다면, 변경된 객체를 다시 컬렉션에 넣지 않는 것 처럼 말이다.

commit 하는 시점에 flush()를 실행된다.
스냅샷 - 값을 딱 읽어온 최초 시점의 객체 상태를 저장해둔다.

지연 로딩(Lazy Loading)

플러시

  • 영속성 컨텍스트의 변경내용을 데이터베이스에 반영
  • flush()를 하면 1차캐시 값들이 사라지나요 ?
    - 아니다. 단지, 쓰기 지연 SQL 저장소에 있는 것들이 DB에 올라갈 뿐이다.
  • 영속성 컨텍스트를 비우지 않음
  • 영속성 컨텍스트의 변경내용을 데이터베이스에 동기화
  • 트랜잭션이라는 작업 단위가 중요 -> 커밋 직전에만 동기화 하면 됨

플러시 발생

• 변경 감지
• 수정된 엔티티 쓰기 지연 SQL 저장소에 등록
• 쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송 (등록, 수정, 삭제 쿼리)

영속성 컨텍스트를 플러시하는 방법 (*중요)

  • em.flush() - 직접 호출
  • 트랜잭션 커밋 - 플러시 자동 호출
  • JPQL 쿼리 실행 - 플러시 자동 호출
    - JPQL 쿼리 실행시 플러시가 자동 으로 호출되는 이유
    em.persist(memberA);
    em.persist(memberB);
    em.persist(memberC);
    
    //중간에 JPQL 실행
    query = em.createQuery("select m from Member m", Member.class);
    List<Member> members= query.getResultList();

준영속 상태

• 영속 -> 준영속
• 영속 상태의 엔티티가 영속성 컨텍스트에서 분리(detached)
• 영속성 컨텍스트가 제공하는 기능을 사용 못함

준영속 상태로 만드는 방법

• em.detach(entity)
특정 엔티티만 준영속 상태로 전환
• em.clear()
영속성 컨텍스트를 완전히 초기화
• em.close()
영속성 컨텍스트를 종료

영속 상태가 될 수 있는 방법

  1. persist()
  2. find() 로 했을 경우 없어서 1차캐시에 올라가는 방법
profile
방문해주셔서 감사합니다🙂

0개의 댓글