영속성 컨텍스트는 JPA 이해에 있어서 가장 중요한 용어이다. 엔티티를 영구 저장하는 환경이라는뜻으로, EntityManager.persist(entity)로 표현할 수 있다.
영속성 컨텍스트는 논리적 개념이다.
EM을 생성하면 눈에 보이지 않는 PersistenceContext라는 공간이 하난 생긴다.
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
// 비영속 상태
Member member = new Member();
member.setId(1L);
member.setName("HelloA");
// 영속 상태 (DB저장을 함)
em.persist(member);
// 준영속
em.detach(member);
//삭제
em.remove(member);
List<Member> resultList = em.createQuery("select m from Member as m", Member.class)
.getResultList();
for (Member member1 : resultList) {
System.out.println("name = " + member1.getName());
}
tx.commit();
} catch (Exception e) {
tx.rollback();
} finally {
em.close();
}
emf.close();
}
}
공간을 분리하는것으로 다음의 이점을 얻을 수 있다.
• 1차 캐시
• 동일성(identity) 보장
• 트랜잭션을 지원하는 쓰기 지연(transactional write-behind)
• 변경 감지(Dirty Checking)
• 지연 로딩(Lazy Loading)
Member member = new Member();
member.setId(1L);
member.setName("HelloA");
em.persist(member);
// 이 상태에서 캐시에 저장
em.find(Member.calss, "member2");
// 캐시 조회
1차캐시에 값을 임의로 저장해놓고 조회가 필요하면 그때 그때 꺼내서 사용한다.
하지만 1차캐시는 한 transcation 안에서만 작동하기때문에 큰 성능적 이득은 없다고 할 수 있다.
Member findMember1 = em.find(101L);
Member findMember2 = em.find(101L);
101 Id를 가진 member를 찾으면, 두 member가 같은 member인것을 보장해준다. 이는 마치 Java에서 같은 주소를 공유하는것과 동일하다.
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
//엔티티 매니저는 데이터 변경시 트랜잭션을 시작해야 한다.
transaction.begin(); // [트랜잭션] 시작
em.persist(memberA);
em.persist(memberB);
//여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.
// ------------------------------------------- //
//커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
transaction.commit(); // [트랜잭션] 커밋
기존에 저장되어있는 값을 update할 때, 굳이 query를 안보내도 알아서 변경을 감지해서 처리해준다.
Member member = new Member();
member.setName("HelloA");
//em.persist(member);
이런식으로 해주면 알아서 commit된다.
이는 flush()되는 상태에서 엔티티 스냅샷과 비교해서 update sql을 생성하고 flush하는것이다.