EntityManagerFactory

  • 하나만 생성하고 애플리케이션 전체 공유

EntityManager

  • 공유x 객체를 대신 저장해주는 느낌 자바의 컬렉션이라고 봐도 됨 고객의 요청이 올 때마다 생성

영속성 컨텍스트 : 엔티티를 영구 저장하는 환경

.persist()
  • 엔티티 매니저를 생성하면 그 안에 1대1로 영속성 컨텍스트 환경이 생김

1. 엔티티 생명주기

1-1. 비영속

Member member = new Member();
member.setId("1L");
member.setUsername(회원1);

1-2. 준영속

em.detach(member)

1-3. 영속

em.persist(member)
  • 영속 상태에서 바로 쿼리가 생성되는게 아니라 트랙잭션 커밋 시점에 쿼리가 진행됨

2. 영속성 컨텍스트의 이점

2-1. 1차 캐시에서 조회

Member member = new Member();
member.setId("member1");
member.setUsername("회원1");

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

//1차 캐시에서 조회
Member findMember = em.find(Member.class, "member1");

-> 이렇게 하면 insert쿼리는 나오나, select 쿼리는 나오지 않는다. 이유는 1차 캐시에서 조회하기 때문이다.

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

-> 이런 경우에도 쿼리가 한 번 나간다. 처음 member1을 가져올 때 jpa가 영속성 컨텍스트에 올려놓고, 다시 한번 조회할 땐 조회 시점에 1차 캐시부터 확인해서 반환하기 때문이다.

2-2. 영속 엔티티의 동일성 보장(같은 트랜잭션 안에서)

Member findMember1 = em.find(Member.class, "member1");
Member findMember2 = em.find(Member.class, "member1");
System.out.println(findMember1 == findMember2)

-> 1차 캐시가 있어서 true 반환

2-3. 엔티티 등록 시 쓰기 지연 가능

EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();

EntityTransaction tx = em.getTransaction();
tx.begin();

em.persist(member1);
em.persist(member2);

tx.commit();

-> 트랜잭션 커밋 순간 insert 쿼리가 2번 날아간다.

  • 상세 동작 과정

    em.persist(member1)  
    

    -> 이 시점에 member1을 1차 캐시에 저장하면서 동시에 insert sql을 생성해서쓰기 지연 sql 저장소에 쌓아둔다.

    em.persist(member2)  
    

    -> member2도 마찬가지로 진행

    tx.commit();
    

    -> 커밋 시점에 쓰기 지연 sql 저장소에 있던 sql이 flush되면서 db에 insert문이 날라감

  • 옵션

    <property name="hibernate.jdbc.batch_size" value="10"/>
    

    -> pom.xml의 옵션으로 10만큼의 쿼리문을 한 방에 보낸다.

2-4. 변경 감지

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

Member member = em.find(Member.class, "member1");
member.setName("member2");

tx.commit();
  • em.persist같은 쿼리가 없어도 update쿼리가 자동으로 나감
  • 스냅샵이란 값을 읽어온 최초시점(영속성 컨텍스트에 처음 들어온 시점)의 상태를 세이브 하는 것
  • 값을 변경하게 되면, commit되는 시점에 flush가 호출되면서 jpa가 엔티티랑 스냅샷을 비교한다. 그 후, update 쿼리를 쓰기 지연 저장소에 만들어 두고, 이를 데이터베이스에 반영하고 commit함.

3. 플러시(flush)

  • 영속성 컨텍스트의 변경사항을 db에 반영
  • 영속성 컨텍스트를 비우는 것이 아님
  • 즉, 영속성 컨텍스트의 변경사항을 db에 동기화시키는 과정
  • 영속성 컨텍스트와 트랜잭션의 주기를 맞춰서 설계해야 문제가 없다.
  • 커밋 직전에만 동기화하면 된다.

3-1. 순서

  1. 변경 감지
  2. 변경 쿼리(등록,수정,삭제)를 쓰기 지연 sql 저장소에 등록
  3. db에 쿼리 전송

3-2. 방법

  1. em.flush() - 직접
  2. 트랜잭션 커밋 - 자동
  3. JPQL 쿼리 실행 - 자동

3-3. 옵션

  1. 커밋이나 쿼리 실행 할 때 플러시(default)
      em.setFlushMode(FlushModeType.AUTO)
    
  2. 커밋할 때만 플러시
      em.setFlushMode(FlushModeType.COMMIT)
    


4. 준영속

Member member1 = em.find(Member.class, 1L);
member1.setName("member2");

em.detach(member1);

tx.commit();

-> 트랜잭션 커밋 시점에 em.find()의 select 쿼리만 나오고, update 쿼리는 나오지 않는다.

4-1. 방법

  1. em.detatch() - 특정 엔티티만
  2. em.clear() - 영속성 컨텍스트 전체 초기화(테스트 할 때 이용)
  3. em.close() - 영속성 컨텍스트 종료

Tags:

Categories:

Date:

Leave a comment