영속성 관리 - 준영속

김득회·2022년 6월 6일
0

JPA

목록 보기
7/11

준영속이란?

영속성 컨텍스트가 관리하는 영속 상태의 엔티티가 영속성 컨텍스트에서 분리된 상태로
영속성 컨텍스트가 해당 엔티티를 더 이상 관리하지 못하면 해당 엔티티는 준영속 엔티티라고 칭한다.
준영속이 되면 영속성 컨텍스트가 제공하는 기능을 사용할 수가 없다.
ex) 1차 캐시, 동일성 보장, 트랜잭션을 지원하는 쓰기 지연, 변경감지, 지연로딩

준영속 상태로 변경하는 방법

  1. em.detach(엔티티) : 특정 엔티티만 준영속 상태로 전환
  2. em.clear() : 영속성 컨텍스트를 완전히 초기화
  3. em.close() : 영속성 컨텍스트를 종료

detach()

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
            (?, ?, ?)
606, 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과 엔티티를 관리하는 모든 정보가 제거 되면서 등록이 되지 않는다.

이렇게 영속 상태였다가 더이상 영속성 컨텍스트가 관리하지 않는 분리된 상태를 준영속 상태라고 한다.
준영속 상태이기 때문에 영속성 컨텍스트가 지원하는 어떠한 기능도 동작하지 않는다.

clear()

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=?
606, 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=?
606, 2022 11:40:14 오후 org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PoolState stop

close()

영속성 컨텍스트를 종료하면, 해당 영속성 컨텍스트가 관리하던 영속상태의 엔티티가 모두 준영속 상태가 된다.

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는 관리되지 않는다.

참고사항

영속상태의 엔티티는 영속성 컨텍스트가 종료되면서 준영속 상태가 된다. 개발자가 직접 준영속 상태로 변경하는 일은 많지 않다.

준영속 상태의 특징

  • 거의 비영속 상태와 가깝다
    • 영속성 컨텍스트가 관리하지 않으므로 1차 캐시, 쓰기 지연, 변경관리, 지연로딩을 포함한 영속성 컨텍스트가 제공하는 어떠한 기능도 사용 및 동작하지 않는다.
  • 식별자 값을 가지고 있다.
    • 비영속 상태일 때에는 식별자 값이 없을 수도 있지만, 준영속 상태는 영속 -> 준영속으로 변경된 상태이기 때문에 반드시 식별자 값을 가지고 있다.
  • 지연로딩 불가
    • 지연로딩은 실제 객체 대신 프록시 객체를 로딩후 해당 객체를 실제 사용할 때 영속성 컨텍스트를 통해 데이터를 불러오는 방법이다. 하지만 준영속 상태에서는 영속성 컨텍스트가 더이상 관리하지 않기 때문에 지연로딩 기능사용 시 문제가 발생한다.
profile
감성 프로그래머 HoduDeuk

0개의 댓글