김영한님의 JPA 강의를 보고 정리한 내용입니다.
EntityManager.persist(entity)로 객체를 영속화한다.
- 생성 비용이 크다
- 생성 비용이 크기 때문에 데이터베이스당 하나만 만들어서 쓰레드간 공유한다.
- Thread-safe 하다
- persist(), find(), remove() 등을 사용해 Entity를 관리한다.
- Thread-safe 하지 않다.
- 생성 시 데이터베이스 연결이 꼭 필요한 시점까지 커넥션을 얻지 않는다.
JPA와 전혀 관계없는 상태일 때 비영속 상태라고 한다. 아래 코드는 객체를 생성만 했을 뿐 JPA와는 전혀 관련없다(=객체를 생성한 상태).
// 객체를 생성한 상태 (비영속)
Member member = new Member();
member.setId(100L);
member.setName("member1");
객체를 생성한 후 EntityManager.persist()에 객체를 저장한 상태를 말한다.
// 객체를 생성한 상태 (비영속)
Member member = new Member();
member.setId(100L);
member.setName("member1");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
// 객체를 저장한 상태 (영속)
em.persist(member);
이때 em.persist()의 경우에만 영속이 되는 것이 아니라, em.find()를 했을 때 1차 캐시에 없는 데이터를 찾아서 1차 캐시에 해당 정보가 저장된 경우도 영속 상태가 된다.
준영속 상태
Member findMember = em.find(Member.class, 101L); // ID = 101L 객체가 영속 상태로 변경
findMember.setName("ASDF"); // 더티 체킹으로 update 쿼리가 날라갈 예정
em.detach(findMember); // 이었으나 준영속 상태로 변경 (JPA에서 관리 안함)
tx.commit(); // select 문만 전송되고 update 문은 전송되지 않음
준영속 상태로 만드는 방법
em.detach() - 특정 엔티티만 준영속 상태로 전환em.clear() - 영속성 컨텍스트를 완전히 초기화em.close() - 영속성 컨텍스트 종료삭제의 경우
// 객체를 생성한 상태 (비영속)
Member member = new Member();
member.setId(100L);
member.setName("member1");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
// 객체를 저장한 상태 (영속)
em.persist(member);
// 객체를 영속성 컨텍스트에서 분리한 상태 (준영속)
em.detach(member);
// 객체를 삭제한 상태 (삭제)
Member findMember = em.find(Member.class, 1L);
em.remove(findMember);
Map<ID, Entity>의 형태로 존재한다고 생각결론: 1차 캐시를 통해 성능상 이점을 가진다.
결론: (같은 트랜잭션 내에서) 같은 식별자에 대한 객체 조회는 동일성을 보장해준다.
EntityManager는 쓰기 지연 SQL 저장소에 insert sql을 쌓아둔다.<property name="hibernate.jdbc.batch_size" value="10"/>로 지정할 수 있다.value 마다 insert query가 실행된다.batch-size에 대한 제한이 없으면 OutOfMemoryException이 발생할 수도 있고, 메모 관리 측면에서도 효율적이지 않다.결론: 영속 시점에 쿼리를 바로 데이터베이스에 보내는 것이 아니라 커밋 직전까지
쓰기 지연 SQL 저장소에 모아둔 뒤 한번에 보내기 때문에 성능상 이점이 있다.
flush() 시점에 스냅샷과 객체를 비교해서 변경된 객체를 찾는다. 이때 영속성 컨텍스트 안에 있는 객체만 변경 감지 기능의 대상이 된다.sql을 데이터베이스에 보낸다. (flush() 끝)이후 추가 예정