

정리 : 1차 캐시는 Map으로 존재하며 키벨류 형태로 영속성 켄텍스트에 저장이 된다. entityManager.find()를 사용하면 1차 캐시를 조회하게 되는데 이때 엔티티가 있으면 반환하고 없으면 데이터베이스에서 찾아서 1차캐시에 키벨류 형태로 저장하고 반환한다.
같은 엔티티가 같은 객체로 인식되는 것을 의미한다. 쉽게 말하면 데이터베이스에서 같은 식별자를 가진 엔티티는 항상 같은 객체로 참조된다는 것을 의미한다.
고객 엔티티 : 고객 엔티티는 고객 식별자(고객 ID)를 가지고 잇다. 같은 고객 ID를 가진 고객 엔티티는 항상 같은객체로 참조된다. 더 쉽게 설명하자면 다음 예제가 있다.
Member findMember1 = entityManager.find(Member.class, 101L);
Member findMember2 = entityManager.find(Member.class, 101L);
System.out.println(findMember1 == findMember2);
PK값 101L을 가지는 엔티티에 대해서는 같은 객체인것을 보장해준다는 것을 의미한다. JPA에가 아닌 MyBatis에서는 조회 결과를 다시 인스턴스로 감싸서 다른 객체가 되어 결과는 false가 나오지만 JPA는 같은 참조값을 같도록 하여 true가 나온다.
참조 : https://jwdeveloper.tistory.com/287
하나의 트렌젝션에서 같은 키값으로 영속성 컨텍스트에 저장된 엔티티 조회시 같은 엔티티 조회를 보장한다. 바로 1차 캐시에 저장된 엔티티를 조회하기 때문에 가능하다.
1차 캐시는 도서관의 책장이다. 독자가 처음 책을 빌려야 할 때 도서관에서 책을 찾아서 빌려야 한다. 하지만 독자가 책을 두번째 빌리는 상황이라면 도서관에서 책을 찾을 필요 없이 바로 책장에 가서 책을 빌려갈 수 있다.
영속성 컨텍스트는 도서관 1차 캐시는 책장, 엔틴티는 책이라고 생각하면 된다.
정리 : 디비에서 가져온 엔티티를 1차 캐시에 저장하고 다시 조회시 1차 캐시에서 저장된 엔티티를 사용한다. 그렇기에 성능적 이점이 있다.

memberA와 memberB를 1차 캐시에 저장하는 persist명령어를 사용하면 쓰기 지연 SQL저장소에 query문을 임시로 저장한다.

commit하는 시점에 쓰기 지연 SQL 저장소에 저장되어 있는 query들을 날려버린다.

member1과 member2를 persist로 1차 캐시에 저장하고 commit을 하는 명령어이다.
persit와 commit 명령어 사이에는 ====으로 구분선을 출력
package hellojpa;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
// code
Member member1 = new Member(150L, "A");
Member member2 = new Member(160L, "B");
em.persist(member1);
em.persist(member2);
System.out.println("===========================");
tx.commit();
em.close();
emf.close();
}
}

코드를 보면 원래 System.out.println("===========================");가 일어나기 전 insert가 되어야 하는것이 정상이다. 하지만 commit을 한 시점에서 한번에 쿼리문이 나가는 것을 볼 수 있다. 다시 말하지만 SQL저장소에 query문을 저장하고 commit시점에 모와서 날리기 때문이다.
참조 : https://daram.tistory.com/265
JPA는 1차 캐시에 데이터베이스에서 처음 불러온 엔티티의 값을 갖고 있다. 그리고 1차 캐시에 저장된 엔티티의 값을 비교후에 변경내용이 있다면 UPDATE SQL문을 사용하여 쓰기 지연 SQL저장소에 담아둔다. 예를들어 중간에 Setter로 값을 변경하는 경우 update문이 쓰기 지연 SQL저장소에 저장된다. 그리고 데이터베이스 커밋 시점에 변경 내용을 자동으로 반영한다. 따로 update문을 호출할 필요 없다.


다음 예제는 persist하여 엔티티를 영속성 컨텍스트에 영구저장을 하고 있다. 그리고 setId를 통하여 값을 lee2로 변경한뒤 flush를 호출하면 insert문이 입력되고 그 다음에 update문이 일어난다. 변경이 없었다면 딱 한번의 insert문이 일어나지만 setter의 값변경 lee2로 변경하여 update문이 날라가게 된다. 그리고 나서 flush()하면 디비에 영구 반영이 된다.
비영속 : 엔티티가 영속성 컨텍스트에 등록되지 않은 상태
준영속 : 엔티티가 영속성 컨텍스트에 등록되어 있지만 아직 디비에 저장되지 않은 상태
영속 : 엔티티가 영속성 컨텍스트에 등록되어 있고 데이터베이스에 저장된 상태