영속성 컨텍스트는 JPA를 이해하는데 가장 중요하다.
- 고객이 요청할 때마다
EntityManagerFactory
를 통해EntityManager
를 생성한다. EntityManager
은 내부적으로 커넥션 풀을 사용해서 DB를 사용하게 된다.
주의
EntityManagerFactory
는 하나만 생성해서 애플리케이션 전체에서 공유해야 한다.Entity Manager
은Threed
간 공유하면 안 된다.사용하고 버려야 한다.
- JPA의 모든 데이터 변경은 트랜잭션 안에서 실행한다.
: entity
를 영구히 저장하는 환경
ex) EntityManger.persist(entity)
Entity
를 영속성 컨텍스트 안에 넣는다.- 영속성 컨텍스트는 논리적인 개념 즉, 눈에 보이지 않는다.
EntityManager
를 통해 영속성 컨텍스트에 접근한다.
//객체만 생성한 상태(비영속)
Mamber member = new Member();
member.setId("member1");
member.setUsername("회원 1");
: 영속성 컨텍스트에 관리 되는 상태
// 객체를 생성한 상태 (비영속)
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
// 객체를 저장한 상태 (영속)
entityManager.persist(member); //이떄 쿼리가 날라가지 않는다.
: 영속성 컨텍스트에 저장되었다가 분리된 상태
//회원 엔티티를 영속성 컨텍스트에서 분리, 준영속 상태
em.detach(member);
: 삭제된 상태
//객체를 삭제한 상태(삭제) 이는 DB에서도 삭제가 된다.
em.remove(member);
- 한 트랜잭션 내에서만 사용 가능하다. 즉 트랜잭션이 종료되면 사라진다.
- JPA에서는 조회시 영속성 컨텍스트를 먼저 조회한다.
Mamber member = new Mamber();
member.setId("member1");
member.setUsername("회원 1");
//1차 캐시에 저장
em.parsist(member);
//1차 캐시에서 조회
Member findMember = em.find(Memeber.class, "member1")
Member findMember2 = em.find(Member.class, "member2");
- 1차 캐시로 반복 가능한 읽기(REPEATABLE READ) 등급의 트랜잭션 격리 수준을 DB가 아닌 애플리케이션 차원에서 제공 한다.
- 같은 트랜잭션 내에서만 동일성을 보장한다.
Member a = em.find(Member.class, "member1");
Member b = em.find(Member.class, "member1");
System.out.println(a == b); //동일성 비교 true
- JPA는 commit을 하기 전까지 insert query를 날리지 않아 최적화할 여지를 준다.
- 그래서 버퍼링 같은 기능을 한다. (쿼리를 모았다가 한 번에 날린다.)
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
//엔티티 매니저는 데이터 변경시 트랜잭션을 시작해야 한다.
tx.begin(); // [트랜잭션] 시작
em.persist(memberA);
em.persist(memberB);
//여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.
//커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
tx.commit(); // [트랜잭션] 커밋
- 커밋된 시점에서 내부적으로
flush()
가 호출된다. 1차 캐시
의 스냅샷과entity
를 비교하여 객체가 변경되었는지 비교한다.- 2번에서 변경사항이 나오면 쓰기 지연
SQL 저장소
에 쿼리를 미리 만들어 저장한다. - DB에
update query
를 반영한다. - DB에
commit
한다.
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin(); // 트랜잭션 시작
// 영속 엔티티 조회
Member memberA = em.find(Member.class, "memberA");
// 영속 엔티티 데이터 수정
memberA.setUsername("hi");
memberA.setAge(10);
/**
/* em.update(member) 이런 코드가 있어야 하지 않을까?
/* Dirty Checking덕분에 안해도 된다.
**/
tx.commit(); // 트랜잭션 커밋
//삭제 대상 엔티티 조회
Member memberA = em.find(Member.class, "memberA");
em.remove(memberA); //엔티티 삭제