영속성 컨텍스트가 관리하는 영속 상태의 엔티티가 영속성 컨텍스트에서 분리된 상태로
영속성 컨텍스트가 해당 엔티티를 더 이상 관리하지 못하면 해당 엔티티는 준영속 엔티티라고 칭한다.
준영속이 되면 영속성 컨텍스트가 제공하는 기능을 사용할 수가 없다.
ex) 1차 캐시, 동일성 보장, 트랜잭션을 지원하는 쓰기 지연, 변경감지, 지연로딩
em.detach(엔티티) 메서드는 특정 엔티티를 준영속 상태로 만든다.
public void detach(Object entity);
public static void testDetached(EntityManager em){
//회원 엔티티 생성 -> 비영속 상태
Member member = new Member();
member.setId("memberA");
member.setUsername("득");
member.setAge(25);
//회원 엔티티 영속 상태
em.persist(member);
//회원 엔티티 영속성 컨텍스트 분리 -> 준영속
//em.detach(member);
}
여기서 em.detach(member)가 없었을 경우에 commit을 수행하면 SQL이 DB로 전달되면서 엔티티가 등록 된다.
INFO: HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
Hibernate:
/* insert hellojpa.domain.Member
*/ insert
into
MEMBER
(age, NAME, ID)
values
(?, ?, ?)
6월 06, 2022 11:20:10 오후 org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PoolState stop
public static void testDetached(EntityManager em){
//회원 엔티티 생성 -> 비영속 상태
Member member = new Member();
member.setId("memberA");
member.setUsername("득");
member.setAge(25);
//회원 엔티티 영속 상태
em.persist(member);
//회원 엔티티 영속성 컨텍스트 분리 -> 준영속
em.detach(member);
}
반면, detach가 선언 되어 있다면 쓰기 지연 SQL 저장소에 있던 SQL과 엔티티를 관리하는 모든 정보가 제거 되면서 등록이 되지 않는다.
이렇게 영속 상태였다가 더이상 영속성 컨텍스트가 관리하지 않는 분리된 상태를 준영속 상태라고 한다.
준영속 상태이기 때문에 영속성 컨텍스트가 지원하는 어떠한 기능도 동작하지 않는다.
em.detach는 하나의 엔티티를 준영속 상태로 만드는 메서드이지만, em.clear()는 영속성 컨텍스트 자체를 초기화하여 영속성 컨텍스트의 모든 엔티티를 준영속 상태로 변경한다.
public static void testClear(EntityManager em){
//엔티티 조회 -> 영속상태
Member member = em.find(Member.class, "memberA");
//영속성 컨텍스트 초기화 -> 준영속으로 전환
em.clear();
//준영속 상태
member.setUsername("득");
}
위 와 같이 em.clear()를 수행하면 해당 메서드 호출 위에 까지는 조회가 가능하지만 호출 후 부터는 준영속 상태로 변경되어 영속성 컨텍스트가 지원하는 변경감지 기능을 포함한 어떠한 기능도 동작하지 않는다.
INFO: HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
Hibernate:
select
member0_.ID as id1_0_0_,
member0_.age as age2_0_0_,
member0_.NAME as name3_0_0_
from
MEMBER member0_
where
member0_.ID=?
6월 06, 2022 11:36:02 오후 org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PoolState stop
반면 em.clear()가 없는 경우에는 보통 업데이트 하는 것 처럼 정상동작 하는 것을 확인할 수 있다.
public static void testClear(EntityManager em){
//엔티티 조회 -> 영속상태
Member member = em.find(Member.class, "memberA");
//영속성 컨텍스트 초기화 -> 준영속으로 전환
//em.clear();
//준영속 상태
member.setUsername("호두");
}
INFO: HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
Hibernate:
select
member0_.ID as id1_0_0_,
member0_.age as age2_0_0_,
member0_.NAME as name3_0_0_
from
MEMBER member0_
where
member0_.ID=?
Hibernate:
/* update
hellojpa.domain.Member */ update
MEMBER
set
NAME=?
where
ID=?
6월 06, 2022 11:40:14 오후 org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PoolState stop
영속성 컨텍스트를 종료하면, 해당 영속성 컨텍스트가 관리하던 영속상태의 엔티티가 모두 준영속 상태가 된다.
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
try{
tx.begin(); //트랜젝션 시작
testClose(em);
tx.commit(); //트랜젝션 종료
em.close(); //영속성 컨텍스트 닫기
}catch (Exception e){
e.printStackTrace();
tx.rollback();
}finally {
em.close();
}
emf.close();
}
public static void testClose(EntityManager em){
Member memberA = em.find(Member.class, "memberA");
Member memberB = em.find(Member.class, "memberB");
System.out.println(memberA.toString());
System.out.println(memberB.toString());
}
위와 같이 close를 수행하면 영속성 컨텍스트가 종료되어 더 이상 memberA, memberB는 관리되지 않는다.
영속상태의 엔티티는 영속성 컨텍스트가 종료되면서 준영속 상태가 된다. 개발자가 직접 준영속 상태로 변경하는 일은 많지 않다.