이번에는 영속상태와 비영속상태에 대해 알아봤습니다.
이번에는 준영속 상태에 대해 알아보고자 한다.
준영속 상태는 앞에서 초반에 얘기했듯이 영속상태였다가 -> 영속성 컨텍스트에서 더이상 관리하지 않을때(분리된)의 상태를 준영속 상태라고 한다.
결과적으로 영속성 컨텍스트에서 관리하지 않기 때문에 영속성 컨텍스트가 제공하는 기능을 사용할 수 없습니다.
영속성 상태의 엔티티를 준영속 상태로 만드는 방법은 3가지로 분류된다.
1. entityManager.detach(entity); // 해당 entity를 detach메서드를 통해 준영속 상태로 만든다.
2. entityManager.clear(); // 영속성 켄텍스트를 초기화한다.
3. entityManager.close(); // 영속성 컨텍스트를 종료한다.
먼저 첫번째인 detach메서드에 대해서 알아보겠습니다.
detach() 메서드는 파라미터로 들어오는 Entity를 준영속 상태로 만든다.
Member member = new Member(28, "YundleYundle");
entityManager.persist(member);
entityManager.detach(member);
위의 코드를 설명하면 다음과 같다.
일단 비영속 상태의 Entity를 만든다음. EntityManager.persist(member)를 통해 비영속 상태의 Entity를 영속상태로 만들었다. 그다음 EntityManager.detach(member)를 통해 준영속 상태로 만들었다.
detach()를 호출하게 되는 순간 1차 캐시부터 쓰기 지연 SQL 저장소까지 해당 Entity를 관리하기 위한 정보가 제거된다. ( 한마디로 영속성 컨텍스트에서 더이상 해당 엔티티를 관리하지 않는다.)
detach메서드가 하나의 Entity를 준영속 상태로 만들었다면 clear()메서드는 영속성 컨텍스트를 초기화해서 해당 영속성 컨텍스트의 모든 Entity를 준영속 상태로 만든다.
Member member = new Member(28, "YundleYundle");
entityManager.persist(member);
entityManager.clear(); // 초기화
member.setAge(29);
clear()를 통해 영속성 컨텍스트가 초기화 되지 않았다면 setAge를 하였기 떄문에 데이터베이스에 반영해야 하지만 entityManager.clear()를 통해 영속성 컨텍스트를 초기화 하였기 때문에 변경 감지는 동작하지 않는다.
영속성 컨텍스트를 종료하면 영속성 컨텍스트가 관리하던 Entity들을 모두 준영속상태로 만든다.
EntityManager em = emf.createEntityManager();
{중간 코드 생략}
...
em.close();
영속 상태의 Entity는 영속성 컨텍스트가 종료되면 준영속 상태가 된다. ( 개발자가 직접 준영속 상태로 만드는일은 드물다고한다 );
1. 비영속 상태와 비슷하다
1차 캐시, 쓰기 지연, 변경 감지, 지연 로딩을 포함한 영속성 컨텍스트가 제공하는 어떤 기능도 사용할 수 없다.
2. 식별자 값을 가지고 있다.
준영속 상태는 한번 영속 상태였기 때문에 반드시 식별자 값을 가지고 있다.
3. 지연 로딩을 할 수 없다.
지연 로딩은 실제 객체 대신 Proxy 객체를 로딩해두고 해당 객체를 실제로 사용할 때 영속성 컨텍스트를 통해 데이터를 불러온다. 하지만 준영속 상태에서는 영속성 컨텍스트가 더이상 관리하지 않기 때문에 지연 로딩시 문제가 발생한다.
영속 -> 준영속 상태로 만들었다면 당연히 준영속 -> 영속상태로 만드는 병합(merge)라는 기능을 제공합니다.
준영속 상태의 Entity를 다시 영속 상태의 Entity로 만들때 병합(merge)라는 방법을 사용하면 된다. merge() 메소드는 새로운 영속 상태의 Entity를 반환한다.
Member mergeMember = entityManager.merge(member);
병합(merge())는 비영속 병합도 지원합니다.
비영속 병합은 비영속 엔티티도 영속상태로 만드는 방법입니다.
Member member = new Member();
Member newMember = entityManager.merge(member);
병합은 파라미터로 넘어온 Entity의 식별자 값으로 영속성 컨텍스트를 조회하고 찾는 Entity가 없다면 DB를 조회한다. 만약에 Entity가 DB에 조차도 없다면 새로운 Entity를 생성해서 병합한다.