[자바 ORM 표준 JPA 프로그래밍] 3.6 준영속
개발서적/자바 ORM 표준 JPA

[자바 ORM 표준 JPA 프로그래밍] 3.6 준영속

Reference. 자바 ORM 표준 JPA 프로그래밍

책 목차 및 이전 글

  • 영속 상태의 엔티티가 영속성 컨텍스트에서 분리된 상태를 의미
  • 준영속 상태의 엔티티영속성 컨텍스트가 제공하는 기능 사용 못함
영속 상태 → 준영속 상태 만드는 방법 3가지
  1. em.detach(entity): 특정 엔티티만 준영속 상태로 전환
  1. em.clear(): 영속성 컨텍스트를 완전히 초기화
  1. em.close(): 영속성 컨텍스트를 종료

3.6.1 엔티티를 준영속 상태로 전환: detach()

public void testDetached() {
    ...
    // 회원 엔티티 생성, 비영속 상태
    Member member = new Member();
    member.setId("memberA");
    member.setUsername("회원A");

    // 회원 엔티티 영속 상태
    em.persist(member);

    // 회원 엔티티를 영속성 컨텍스트에서 분리, 준영속 상태
    em.detach(member);

    transaction.commit();   //트랜잭션 커밋
}
  • 영속성 컨텍스트에서 관리하던(1차 캐시, 쓰기 지연 SQL 저장소) 정보를 제거
  • 준영속 상태: 영속 상태였다가 영속성 컨텍스트가 관리하지 않는 상태 (분리된 상태)

3.6.2 영속성 컨텍스트 초기화: clear()

  • em.detach() 는 특정 엔티티 하나, em.clear() 는 모든 엔티티를 준영속 상태로 변경
//엔티티 조회, 영속 상태
Member member = em.find(Member.class, "memberA");

em.clear();     //영속성 컨텍스트 초기화

//준영속 상태
member.setUsername("changeName");
  • 영속성 컨텍스트에 모든 것이 초기화
  • 준영속 상태이므로 변경 감지는 동작하지 않음, 따라서 데이터베이스도 반영 안됌

3.6.3 영속성 컨텍스트 종료: close()

  • 종료하면 영속성 컨텍스트 관리하던 영속 상태 엔티티가 모두 준영속 상태로 변경
  • 영속 상태의 엔티티는 주로 영속성 컨텍스트가 종료되면서 준영속 상태로 변경
    → 개발자가 직접 준영속 상태로 만드는 일은 거의 없음

3.6.4 준영속 상태의 특징

  • 거의 비영속 상태에 가깝다
    • 영속성 컨텍스트가 관리하지 않으므로 1차 캐시, 쓰기 지연, 등 어떠한 기능도 동작 안함
  • 식별자 값을 가지고 있다
    • 비영속 상태는 식별자 값이 없을 수도 있지만 준영속 상태는 반드시 식별자 값을 가짐
  • 지연 로딩을 할 수 없다
    • 지연 로딩은 실제 객체 대신 프록시 객체를 로딩하여 영속성 컨텍스트를 통해 데이터를 불러오는 방법
    • 영속성 컨텍스트가 관리하지 않으므로 지연 로딩시 문제 발생

 

*프록시 객체: (8.1 프록시 참고)

하이버네이트가 강제로 만든 가짜 클래스인 HibernateProxy 객체

  • 실제 클래스를 상속 받아서 생성
    • 하이버네이트가 내부적으로 상속받아서 생성
  • 실제 클래스와 겉 모양이 동일
  • 사용하는 입장에서는 진짜 객체인지 프록시 객체인지 구분하지 않고 사용
  • 프록시 객체는 실제 객체의 참조(target)을 보관
  • 프록시 객체를 호출하면 프록시 객체는 실제 객체의 메소드를 호출

프록시 참조 출처: https://ict-nroo.tistory.com/131

3.6.5 병합: merge()

  • 준영속 상태의 엔티티를 다시 영속 상태로 변경하는 기능
  • 준영속 상태의 엔티티를 받아 그 정보로 새로운 영속 상태의 엔티티를 반환
그림 실행 순서
  1. merge() 실행
  1. 파라미터로 넘어온 준영속 엔티티의 식별자 값으로 1차 캐시 엔티티 조회
    - 만약 1차 캐시에 엔티티가 없으면 데이터베이스에서 조회 후 1차 캐시 저장
  1. 조회한 영속 엔티티에 member 엔티티의 값을 채움
    → mergetMember의 "회원1"이 member 엔티티의 "회원명변경"으로 변경 됌)
  1. mergetMember를 반환
  1. 병합이 끝나고 트랜잭션 커밋을 통해 변경감지 기능이 동작. 변경내용이 데이터베이스에 반영

 

  • em.contains(entity) : 영속성 컨텍스트가 파라미터에 엔티티를 관리하는지 확인하는 메소드
    → member는 false 반환, mergetMember는 true 반환
    merge()준영속 엔티티를 참조하던 변수영속 엔티티 참조로 변경하는 것이 안전
//Member mergeMember = em2.merge(member); // 기존 코드
member = em2.merge(member);

비영속 병합

  • merge() 는 비영속 엔티티도 영속 상태로 변경이 가능
Member member = new Memeber();
Member newMember = em.merge(member); //비영속 병합
tx.commit();
  • 파라미터로 넘어온 엔티티의 식별자 값으로 영속성 컨텍스트를 조회
    → 영속성 컨텍스트에 없으면 데이터베이스에서 조회
    → 데이터베이스에서도 없으면 새로운 엔티티를 생성해서 병합
  • 병합은 준영속, 비영속을 신경쓰지 않음
  • 조회할 수 있으면 불러서 병합, 조회가 안되면 새로 생성해서 병합 (save or update)

 

이미지 출처: https://ultrakain.gitbooks.io/jpa/content/chapter3/chapter3.4.html