JPA에서 가장 중요한 2가지
웹 어플리케이션을 개발한다면, 엔티티 매니저 팩토리를 통해서 고객에게 요청이 올때마다 엔티티 매니저를 생성한다.
엔티티 매니저는 데이터 커넥션을 사용해서 DB를 사용하게 된다.
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(member);
DB에 저장되는 시점은 커밋 이후
//회원 엔티티를 영속성 컨텍스트에서 분리, 준영속 상태
em.detach(member);
//객체 삭제
em.remove(member);
detach
의 경우에는 DB에는 값이 남아있고, 영속성 컨텍스트에는 남아있지 않고,
remove
의 경우에는 DB에도 값을 지우는?
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
em.persist(member);
//1차 캐시에서 조회
Member findMember = em.find(Member.class, "member1");
Member findMember2 = em.find(Member.class, "member2");
Member a = em.find(Member.class, "member1");
Member b = em.find(Member.class, "member1");
System.out.println(a == b); // 동일성 비교 true
1차 캐시로 반복 가능한 읽기 등급의 트랜잭션 격리 수준을 데이터베이스가 아닌 애플리케이션 차원에서 제공
이와 관련하여, 캐시 덕분에 동일성이 보장된다는 말을 보고
그럼 데이터베이스에서 받아오는건 동일성이 보장안될까? 가 궁금해져 작은 실험을 함.
DB 쿼리로 보내서 값을 가져온건 동일할까?
동일하다.
쉽게 말해 em.persist()를 한다고 해서 바로 데이터베이스에 쿼리를 날리지 않음.
트랜잭션 커밋까지 해야 통째로 보냄.
쉽게 말해 트랜잭션이 커밋했을때, 값이 바뀐게 있다면, 자동으로 변경해줌.
자세히 말하자면, 최초로 (데이터베이스에서 값을 가져왔건, find로 찾았건간에)만들어진 엔티티를 스냅샷에 저장한다.
그 후에 만약 값이 변경했다면, Entity
에 변경된 값이 저장되어있을 것이다.
트랜잭션이 커밋할 때, flush
가 호출되면서 그때 JPA가 Entity
와 스냅샷을 전부 비교하여 바뀐 곳이 있다면, SQL에 Update를 만들어둬서 데이터베이스에 커밋하게 된다.
Member memberA = em.find(Member.class, "memberA");
em.remove(memberA); // 엔티티 삭제
플러시 이후에도 1차 캐시 값들은 남아있다.
JPQL 쿼리 실행시 플러시가 자동으로 호출되는 이유
em.persist(memberA);
em.persist(memberB);
em.persist(memberC);
// 커밋, 플러시를 따로 안했기 때문에 아직 데이터베이스로 저장이 안됨.
// 중간에 JPQL 실행
query = em.createQuery("select m from Member m", Member.calss);
// 데이터를 아직 저장하지 않아서 위 세 맴버 조회 안됨.
이러한 것들 때문에 문제가 발생할 수 있어서 JPQL 쿼리를 실행하게 되면 무조건 플러시가 자동호출된다.
그러면 중간에 JPQL을 실행하고 맴버 ABC가 조회된다.
em.setFlushMode(FlushModeType.COMMIT)
거의 사용할 일 없다. 커밋을 굳이 음 그렇다.
detach
를 쓰게 되면 이후에 set
을 통해 내용을 바꿔도 변경감지가 안됨.
(엔티티 기능이 적용 안됨)
clear
의 경우 1차 캐시의 내용을 전부 날리기 때문에 요청을 새로 한다.
그렇기 때문에 테스트할때 눈으로 영속성 컨텍스트에서 요청하는 것을 다시금 보고 싶을때 쓰인다고 한다.