영속성 컨텍스트는 엔티티를 영구 저장 하는 환경 이다. 영속성 컨텍스트는 애플리케이션과 DB 사이에서 객체를 보관하는 가상 DB 역할을 하며, 엔티티 매니저를 통해 엔티티를 저장하거나 조회하면 엔티티 매니저는 영속성 컨텍스트에 엔티티를 보관하고 관리한다.
//객체만 생성한 비영속 상태
Member member = new Member();
member.setId("member");
member.setUsername("회원");
//객체만 생성한 비영속 상태
Member member = new Member();
member.setId("member");
member.setUsername(“회원”);
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
//객체를 저장한 상태(영속)
em.persist(member);
em.persist(member);
이런 준영속 상태의 특징 으로는 1차 캐시, 쓰기 지연, 변경 감지, 지연 로딩등 영속성 컨텍스트가 제공하는 기능이 작동하지 않는다.
em.remove(member);
Member a = em.find(Member.class, "member");
Member b = em.find(Member.class, "member");
System.out.println(a==b) // true
1차 캐시로 반복 가능한 읽기 등급의 트랙잭션 격리 수준을 데이터베이스가 아닌 애플리케이션 차원에서 제공해 준다.
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
//엔티티 매니저는 데이터 변경시 트랜잭션을 시작.
transaction.begin(); // [트랜잭션] 시작
em.persist(memberA);
em.persist(memberB);
//여기까지 INSERT SQL을 데이터베이스에 보내지 않고 모아 둔다.
//커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
transaction.commit(); // [트랜잭션] 커밋
em.persist()로 객체를 영속성 컨텍스트에 저장하여도 DB에 곧장 Insert 쿼리를 보내지 않는다. SQL 쿼리들을 모아둔 후 flush 될 때(영속성 컨텍스트의 변경내용을 DB에 반영할 시점) 모아둔 쿼리를 Insert 쿼리를 보낸다. 이를 쓰기 지연이라 한다. 이를 통하여 성능이 향상될 수 있다.
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin(); // [트랜잭션] 시작
// 영속 엔티티 조회
Member member = em.find(Member.class, "member");
// 영속 엔티티 데이터 수정
member.setName("hi");
member.setAge(10);
transaction.commit(); // [트랜잭션] 커밋
영속성 컨텍스트에서 엔티티를 조회해서 해당 엔티티를 수정한다 할 때, 조회한 엔티티를 다시 업데이트를 하지 않아도 영속성 컨텍스트내의 스냅샷과 엔티티를 비교해 변경된 엔티티가 있으면 update 쿼리를 자동 생성한다.이 Update 쿼리도 쓰기 지연이 가능하다.
지연로딩은 연관 관계 매핑되어 있는 엔티티를 조회 시 프록시 객체를 우선 반환하며, 실제 필요한 데이터를 쿼리를 날려 가져오는 기능이다.
플러시는 영속성 컨텍스트의 변경 내용을 DB에 반영한다. 영속성 컨텍스트의 엔티티를 지우는게 아니라 변경 내용을 DB에 동기화하는 것이다.
플러시의 흐름으로는
1. 변경 감지가 동작하여 스냅샷과 비교해서 수정된 엔티티를 찾는다.
2. 수정된 엔티티에 대해 수정 쿼리를 만들어 SQL 저장소에 등록한다.
3. 쓰기 지연 SQL 저장소의 쿼리를 DB에 전송한다.