영속성 컨텍스트 전에 JPA의 Entity Manager Factory, Entity Manager, Entity를 소개하면 아래와 같다.

//공장 만들기, 비용이 아주 많이 든다.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpabook");
데이터베이스의 테이블과 매핑되는 자바 객체
⇒이를 통해 자바 애플리케이션에서 데이터베이스의 데이터를 객체로 다룰 수 있습니다.
// 저장
em.persist(member);

//객체를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
//객체를 저장한 상태(영속)
em.persist(member);
//회원 엔티티를 영속성 컨텍스트에서 분리, 준영속 상태
em.detach(member);

⇒ 그림과 같이 식별자 값으로 엔티티를 찾는다. (Map 형식)

EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
//엔티티 매니저는 데이터 변경 시 트랜잭션을 시작해야 한다.
transaction.begin(); //[트랜잭션] 시작
em.persist(memberA);
em.persist(memberB);
//여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.
//커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
transaction.commit(); //[트랜잭션] 커밋


⇒ 쓰기 지연 SQL 저장소에 모인 쿼리를 데이터베이스에 보내고 실제 데이터베이스 트랜잭션을 커밋한다.
⇒이런 개발 방식의 문제점은 수정 쿼리가 많아지는 것은 물론이고 비즈니스 로직을 분석하기 위해 SQL을 계속 확인해야 한다. 결국 직접적이든 간접적이든 비즈니스로직이 SQL에 의존하게 된다.
그래서 JPA는 변경 감지를 통해 엔티티를 수정한다.
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin(); //[트랜잭션] 시작
//영속 엔티티 조회
Member memberA = em.find(Member.class, "memberA");
//영속 엔티티 데이터 수정
memberA.setUsername("hi");
memberA.setAge(10);
//em.update(member) 이런 코드가 있어야 하지 않을까?
transaction.commit(); //[트랜잭션] 커밋

⇒ 단, 변경 감지는 영속석 컨텍스트가 관리하는 영속 상태의 엔티티에만 적용된다.
UPDATE MEMBER
SET
NAME=?,
AGE=?,
GRADE=?,
...
WHERE
id=?
Member memberA = em.find(Member.class, "memberA"); //삭제 대상 엔티티 조회
em.remove(memberA); //엔티티 삭제
- 변경 감지가 동작해서 영속성 컨텍스트에 있는 모든 엔티티를 스냅샷과 비교해서 수정된 엔티티를 찾는다. 수정된 엔티티는 수정 쿼리를 만들어 쓰기 지연SQL 저장소에 등록한다.
- 쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송한다.
플러시하는 방법 3가지
em.detach(entity) : 특정 엔티티만 준영속 상태로 전환
em.clear() : 영속성 컨텍스트를 완전히 초기화한다.
em.close() : 영속성 컨텍스트를 종료한다.
public void testDetached() {
...
//회원 엔티티 생성, 비영속 상태
Member member = new Member();
member.setId("memberA");
member.setUsername("회원A");
//회원 엔티티 영속 상태
em.persist(member);
//회원 엔티티를 영속성 컨텍스트에서 분리, 준영속 상태
em.detach(member);
transaction.commit(); //트랜잭션 커밋
}
⇒ 위에선 memberA Entity가 영속성 컨텍스트에서 분리되어 준영속 상태가 된다.
//엔티티 조회, 영속 상태
Member member = em.find(Member.class, "memberA");
em.clear(); //영속성 컨텍스트 초기화
//준영속 상태
member.setUsername("changeName");
⇒ 위에선 member의 이름을 변경해도 데이터베이스에 반영되지 않는다.
⇒ 영속성 컨텍스트가 종료되어 더는 memberA, memberB가 관리되지 않는다.

‼ 영속 상태의 엔티티는 주로 영속성 컨텍스트가 종료되면서 준영속 상태가 된다. 개발자가 직접 준영속 상태로 만드는 일은 드물다.
준영속 상태의 엔티티를 다시 영속 상태로 변경하려면 merge를 사용한다.
⇒ 준영속 상태의 엔티티를 받아서 그 정보로 새로운 영속 상태의 엔티티를 반환한다.
참고로 병합은 비영속 엔티티도 영속 상태로 만들 수 있다.