작성
·
10
0
public static void manin(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
// code
try {
Member member1 = new Member();
member1.setUsername("user1");
em.persist(member1);
em.flush();
em.clear();
Member refMember = em.getReference(Member.class, member1.getId());
System.out.println("refMember = " + refMember.getClass()); // Proxy
// em.detach(refMember); -> 정상적인 exception 발생
em.close(); // -> exception 발생하지 않음
System.out.println("refMember = " + refMember.getUsername());
tx.commit(); // 커밋하는 순간 데이터베이스에 sql문을 보낸다. -> 쓰기 지연
} catch (Exception e) {
tx.rollback();
e.printStackTrace();
} finally {
em.close();
}
emf.close();
}
}
em.detach()를 호출할땐 LazyInitializationException이 발생하는데,
em.close()를 호출하면 예외가 발생하지 않고 refMember의 프록시가 초기화 되어서
refMember.getUsername()이 정상적으로 출력됩니다.
영한님 강의에선 em.close()를 호출해도 예외가 발생하던데, 왜 이렇게 동작하는지 궁금해서 질문 드립니다!
답변 1
0
안녕하세요, 인프런 AI 인턴입니다.
재용님이 제기하신 질문은 JPA 프록시 객체의 초기화와 관련된 내용으로, em.close()
호출 후 특별한 예외 없이 프록시 객체가 작동하는 이유에 대한 것입니다. 강의 중 em.detach()
와 em.close()
의 차이로 인해 발생하는 동작에서 혼동을 겪으신 것 같네요.
기본적으로 em.detach(refMember)
는 해당 엔티티를 영속성 컨텍스트에서 분리시켜 프록시 초기화를 막아 LazyInitializationException을 발생시킵니다. 반면, em.close()
는 영속성 컨텍스트 전체를 종료하는데, 그동안 트랜잭션이 종료되지 않은 상태라면, 프록시 초기화를 통해 실제 엔티티 데이터를 사용할 수 있게 됩니다.
이와 관련된 유사한 사례와 더 깊은 이해를 돕는 답변은 지식공유자님이 설명하신 내용 중에 찾을 수 있습니다. 하이버네이트의 버전 변화에 의해 이러한 상황이 발생할 수 있는데요. 프록시 강의 중 초기화 실패 예제에 대한 질문에서는 하이버네이트의 버전 변경에 따른 isOpenOrWaitingForAutoClose
메서드의 사용으로 인해 이러한 동작이 설명되고 있습니다.
하이버네이트 5.4.1.Final 이후 버전부터는 트랜잭션이 유지된다면 em.close()
후에도 프록시 초기화가 허용되도록 변경되었습니다. 따라서, 예외가 발생하지 않는 것이 현재의 정상적인 동작입니다.
이 설명이 재용님의 이해에 도움이 되기를 바랍니다.
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.