실제 JPA가 어떻게 동작하는 지를 이해할 때 중요한 개념이다.
JPA는 다음과 같은 구조로 동작한다. EMF에서 EM을 생성해서 각 요청마다 매핑해주어 DB Connection을 할당받아 DB에 접근한다.
영속성 컨텍스트를 바로 해석하면 Entity를 영구 저장하는 환경이라는 뜻이다. 이는 논리적인 개념으로 눈에 보이지 않는다. 중요한 점은 영속성 컨텍스트는 트랜잭션이 시작되면 생겨나고, 트랜잭션이 종료되면 삭제된다.
이 영속성 컨텍스트의 상태를 통해 Entity의 상태를 알아보자.
영속성 컨텍스트와 전혀 관계가 없는 상태로, EntityManager를 사용하지 않는 상태이다.
Member member = new Member();
member.setName("Hello");
영속성 컨텍스트에 관리되는 상태로 EntityManager를 사용하여 등록한 상태를 말한다.
em.persist(member);
이렇게 하면 member 객체가 영속성 컨텍스트에 등록된다. 이 시점에서는 쿼리가 날아가지 않는다. 쿼리는 트랜잭션이 커밋될 때 이 persist에 해당하는 INSERT 쿼리가 날아가게 되고, 이 시점에서는 영속성 컨텍스트에 등록되는 과정이다. 즉, Application과 DB 사이에 다른 계층이 하나 존재한다고 보면 된다.
영속성 컨텍스트에 저장된 엔티티를 영속성 컨텍스트에서 내리는 과정이다.
em.detach(member);
객체를 삭제하는 상태이다.
em.remove(member);
이 영속성 컨텍스트 덕분에 JPA의 장점이었던, 1차 캐시, 동일성 보장, 쓰기 지연, 지연 로딩, 변경 감지 등의 기능을 제공해줄 수 있다.

트랜잭션이 커밋되기 전까지 변경 사항은 영속성 컨텍스트에 저장된다고 했다. 그래서 만약 member1이라는 아이디를 가지는 member 객체를 persist해도 DB에 이 객체가 등록되는 쿼리가 날아가지 않고 영속성 컨텍스트 내에 있는 1차 캐시에 들어간다. (Git에서 변경 사항이 스테이징 되는 것처럼)
이후 방금 넣은 객체를 조회하면 DB가 아니라 이 1차 캐시에서 가져오고자 하는 객체가 있는 지를 확인해서 있으면 가져온다.
만약, 1차 캐시에 해당하는 객체에 대한 정보가 없다면 DB를 조회하여 해당 객체를 꺼내 1차 캐시에 저장하고 난 후에 객체를 반환한다.
이 1차 캐시는 모든 사용자들이 공유하면서 사용하는 캐시가 아니기 때문에 성능 향상이 되긴 하지만 의미있는 수준은 아니라는 점을 참고할 것.
앞선 설명에서 JPA는 자바 컬렉션에서 객체를 꺼내는 것처럼 객체의 동일성을 보장해줄 수 있다고 했는데, 이 보장이 영속성 컨텍스트가 해주는 것이다.
EntityManager는 데이터를 변경할 시에 반드시 트랜잭션을 시작해야 한다고 했다. 그래야 영속성 컨텍스트도 생성되기 때문이다. 여기서 persist를 통해 데이터를 저장해도 바로 SQL을 통해 객체를 DB로 보내지 않는다.

만약 em.persist(memberA);라는 코드가 실행되면 memberA는 1차 캐시에 저장됨과 동시에 영속성 컨텍스트 내에 있는 쓰기 지연 SQL 저장소에 SQL 형태로 저장된다. em.persist(memberB);가 실행되도 마찬가지이다.

이후, commit이 되면 쓰기 지연 SQL 저장소에 있던 SQL문들이 flush되어 DB로 날아간다. 이후, commit되어 DB에 변경 사항이 반영되게 된다.
JPA에서는 트랜잭션을 사용하면 수정 사항을 알아서 감지한다고 했다.

영속성 컨텍스트 내에 있는 1차 캐시에서는 스냅샷이라는 필드가 있다. 이 스냅샷 필드는 가장 처음 영속성 컨텍스트가 실행되었을 때의 객체 상태를 저장해둔 필드이다. 만약, 엔티티가 수정된다면 flush 될 때, 이 1차 캐시 안에 있는 스냅샷과 엔티티 필드를 비교하여 수정된 부분을 UPDATE SQL문을 통해 쓰기 지연 SQL 저장소로 가게 되고 flush 되어 DB로 전달된 후, 커밋된다.
이때, 불안한 마음에 변경 사항을 따로 저장할 경우에는 작은 문제들이 생길 수 있다. JPA에서는 값이 바뀌면 무조건 UPDATE 쿼리가 생성된다고 봐야 하기 때문에 따로 변경 사항을 저장하는 코드를 만든다면 중복된 쿼리가 발생하는 등의 문제가 생길 수 있다.
앞에서 말했던 flush는 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영하는 것이다. flush가 발생하면 일어나는 이벤트는 다음과 같다.
flush를 하려면
flush를 사용한다고 해서 영속성 컨텍스트가 비워지는게 아니라 단순히 쓰기 지연 SQL 저장소의 SQL문을 DB에 반영시키는 것이다.
영속 상태의 Entity가 영속성 컨텍스트에서 분리되는 것이다.(detach). 이렇게 되면, 영속성 컨텍스트가 제공하는 기능을 사용하지 못하게 된다. 준영속 상태로 만드는 방법은