출처 | 나무소리
영속성 컨텍스트는 EntityManager 단위로 관리된다.
EntityManager.persist() : 를 통한 영속객체 등록은 우선 해당 객체가 1차 캐시에 저장되고 일반적으로
----> 트랜잭션이 커밋되는 시점에 Insert 쿼리가 데이터베이스에 반영된다.
객체의 변경 사항은 1차 캐시의 스냅샷(snapshot) 정보를 통해 판별
영속 객체의 상태가 변경되면, 1차 캐시의 스냅샷과 비교하고 다를 경우, Update 쿼리를 생성 SQL 저장소에 저장한다.

플러시(flush)는 영속성 컨텍스트의 내용을 데이터베이스와 동기화 하는 것을 의미
플러시 3가지 방식
플러시를 실행한 이후에도 영속성 컨텍스트의 내용은 그대로 유지된다.
"영속 객체"는 총 4가지로 구분된다.
비영속(New) : 영속성 컨텍스트로 관리되기 이전 순수 객체 상태
영속(Managed) : 영속성 컨텍스트로 등록되고 관리되는 상태
준영속(Detached) : 영속성 컨텍스트의 관리에 있다가 분리된 상태(Managed -> Detached)
삭제(Removed) : 영속 데이터의 삭제를 위한 상태(EntityManager.remove())
public class CustomerJpaExam {
public static void main(String[] args) {
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("customer-exam");
EntityManager em = entityManagerFactory.createEntityManager();
EntityTransaction et = em.getTransaction();
et.begin();
try{
Customer customer = new Customer("ID0003", "Hong"); // 새로운 객체 생성 --> 비영속상태(new)
em.persist(customer);// 비영속상태 -> "영속상태"(Managed)로 바꾸는 과정
em.flush(); // 이렇게 flush를 진행하면 데이터베이스와 동기화가 된다. 지금은 commit을 진행하지 않았다.
// 여기서 실행을 하게 되면 persist에 대한 Insert쿼리가 전송된다.
}
catch (Exception e)
{
et.rollback();
}
finally {
em.close();
}
entityManagerFactory.close();
}
}

em.persist(): 이렇게 flush를 진행하면 데이터베이스와 동기화가 된다. 지금은 commit을 진행하지 않았다.
commit() : 진행하면 flush()가 자동으로 실행된다.
public class CustomerJpaExam {
public static void main(String[] args) {
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("customer-exam");
EntityManager em = entityManagerFactory.createEntityManager();
EntityTransaction et = em.getTransaction();
et.begin();
try{
Customer customer = new Customer("ID0005", "Hong"); // 새로운 객체 생성 --> 비영속상태(new)
em.persist(customer);// 비영속상태 -> "영속상태"(Managed)로 바꾸는 과정
em.flush();
// 이렇게 flush를 진행하면 데이터베이스와 동기화가 된다. 지금은 commit을 진행하지 않았다.
// 여기서 실행을 하게 되면 persist에 대한 Insert쿼리가 전송된다.
// 데이터베이스에 commit이 진행되지 않았음
Query query = em.createQuery("SELECT c FROM Customer c", Customer.class);
List<Customer> customers = query.getResultList();
System.out.println(customers);
}
catch (Exception e)
{
et.rollback();
}
finally {
em.close();
}
entityManagerFactory.close();
}


flush를 사용하지 않는다면?
try{
Customer customer = new Customer("ID0005", "Hong"); // 새로운 객체 생성 --> 비영속상태(new)
em.persist(customer);// 비영속상태 -> "영속상태"(Managed)로 바꾸는 과정
// em.flush();
// 이렇게 flush를 진행하면 데이터베이스와 동기화가 된다. 지금은 commit을 진행하지 않았다.
// 여기서 실행을 하게 되면 persist에 대한 Insert쿼리가 전송된다.
// 데이터베이스에 commit이 진행되지 않았음
Query query = em.createQuery("SELECT c FROM Customer c", Customer.class);
List<Customer> customers = query.getResultList();
System.out.println(customers);
et.commit();
}


public class CustomerJpaExam {
public static void main(String[] args) {
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("customer-exam");
EntityManager em = entityManagerFactory.createEntityManager();
EntityTransaction et = em.getTransaction();
et.begin();
try{
Customer customer = new Customer("ID0005", "Hong"); // 새로운 객체 생성 --> 비영속상태(new)
em.persist(customer);// 비영속상태 -> "영속상태"(Managed)로 바꾸는 과정
Customer foundCustomer = em.find(Customer.class,"ID0005"); // 여기선 영속상태로 1차캐시에 들어가있기 때문에, SELECT 쿼리를 보내지 않는다.
et.commit();
}
catch (Exception e)
{
et.rollback();
}
finally {
em.close();
}
entityManagerFactory.close();
}

가운데 em.detach(customer);를 삽입한다면?
이전 코드에서 ID0005를 넣어놨기 때문에 -> 영속상태로 만들어놨기 때문에
em.detach(customer)로 설정하여 준영속상태로 변경했음
