그림과 같이 사용자의 요청이 들어오게되면 매니저 팩토리에서 사용하기 위한 엔티티 매니저를 생성하여 사용합니다.
엔티티매니저를 생성하게되면, 영속성 컨텍스트가 생성됩니다.
엔티티는 위와같은 상태가 존재하는데 아래와 같이 코드에 따라 생명주기가 바뀌게됩니다.
// 객체를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
// 객체를 저장한 상태(영속)
em.persist(member);
// 회원 엔티티를 영속성 컨텍스트에서 분리(준영속)
em.detach(member);
// 객체를 삭제한 상태
em.remove(member);
영속성 컨텍스트는 애플리케이션과 DB사이에 존재하는것으로, 이런 매커니즘에서 얻을수있는게 되게 많습니다.
@ID가 key이며 Entity가 Value일경우 DB에 접근없이 캐쉬에서 member1의 정보를 조회할 수 있습니다.
허나 위처럼 member2처럼 캐쉬에 데이터가 없는경우 DB에 조회후 member2의 정보를 얻고 난 후 캐시에 저장합니다.
// INSERT START
Member member = new Member();
member.setId(101L);
member.setName("Hello JPA");
em.persist(member);
// SELECT
Member findMember = em.find(Member.class, 101L);
System.out.println("find Member ID = " + findMember.getId());
System.out.println("find Member NAME = " + findMember.getName());
INSERT 후 SELECT가 실행되는 코드입니다.
하지만 SELECT문이 로그에는 출력되지 않는걸 확인할수있습니다. 1차캐시(영속성 컨텍스트)에 데이터가 있기때문에 DB에서 조회하지않습니다.
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
//엔티티 매니저는 데이터 변경시 트랜잭션을 시작해야 한다.
transaction.begin(); // [트랜잭션] 시작
em.persist(memberA); // 1차 캐시에 저장 INSERT SQL 생성(쓰기 지연 SQL저장소에 저장)
em.persist(memberB); // 1차 캐시에 저장 INSERT SQL 생성(쓰기 지연 SQL저장소에 저장)
//여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.
//커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
transaction.commit();
// [트랜잭션] 커밋 -> 쓰기지연 SQL저장소에서 flush(쓰기) 되면서 DB에 저장됨
// 후 실제DB에 커밋이 됨.
버퍼링에 모아서 한번에 쓰게되어 이러한 이점들을 얻을수 있게되며 persistence.xml파일에 버퍼의 갯수를 설정하여 사용이 가능합니다.
Member member = em.find(Member.class, 150L);
member.setName("ZZZZZ");
위처럼 setName으로 member객체의 값 변경 시 UPDATE 쿼리가 실행된는걸 확인 할 수 있습니다.
별도에 업데이트 함수호출없이 set로 인하여 DB가 업데이트 되는 상황입니다.
1. commit 시 flush가 호출됩니다.
2. 1차 캐시에 @id, Entity 뿐만아니라 스냅샷이라는 정보도 저장됩니다.
스냅샵은 값을 읽어온 최초 시점을 스냅샷에 저장해둔 상태입니다.
3. Entity가 변경후 commit시 JPA가 1차캐시에 Entity - 스냅샷을 서로 비교합니다.
4. 변경됐을때는 SQL Update 쿼리가 진행됩니다.
영속성 컨텍스트의 변경 내용을 DB에 반영하는것입니다. 커밋이될때 또는 JPQL시 플러시가 발생됩니다.
em.persist(memberA);
em.persist(memberB);
em.persist(memberC);
//중간에 JPQL 실행
query = em.createQuery("select m from Member m", Member.class);
// members에서는 memberA,memberB,memberC의 정보가 모두 조회 됨
List<Member> members= query.getResultList();
영속 상태의 엔티티가 영속성 컨텍스트의 분리(detached)가 된 상태이며, 영속성 컨텍스트가 제공하는 기능을 사용하지 못합니다.
• em.detach(entity) : 특정 엔티티만 준영속 상태로 전환
• em.clear() : 영속성 컨텍스트를 완전히 초기화
• em.close() : 영속성 컨텍스트를 종료