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. 순서
- 변경 감지
- 변경 쿼리(등록,수정,삭제)를 쓰기 지연 sql 저장소에 등록
- db에 쿼리 전송
3-2. 방법
- em.flush() - 직접
- 트랜잭션 커밋 - 자동
- JPQL 쿼리 실행 - 자동
3-3. 옵션
- 커밋이나 쿼리 실행 할 때 플러시(default)
em.setFlushMode(FlushModeType.AUTO)
- 커밋할 때만 플러시
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. 방법
- em.detatch() - 특정 엔티티만
- em.clear() - 영속성 컨텍스트 전체 초기화(테스트 할 때 이용)
- em.close() - 영속성 컨텍스트 종료
Leave a comment