반응형
LazyInitializationException : 준영속 상태의 엔티티에 지연로딩을 시도했을때 발생하는 exception
LazyInitializationException에 대해 이해하기 위해서는 일단 영속성 컨텍스트와 Hibernate의 메커니즘에 대해 이해하고 있어야 한다.
아래 코드의 동작방식을 영속성 컨텍스트에 대입해서 생각해보자
EntityManager em = emf.createEntityManager();
em.getTransation().begin();
User user = new User();
user.setId(1L);
user.setName("myname");
user.setPhone("01012341234");
em.persist(user);
System.out.println(user.getName());
em.getTransation().commit();
- 새로운 user 엔티티를 생성하고 persist를 이용해 영속성을 부여한다.
- 이 상태는 영속성 컨텍스트에 1차 캐시로 저장되며 동시에 "쓰기 지연 저장소" 에 저장되어 있는 상태
- user는 Hibernate에서 만들어낸 User 엔티티를 상속받는 Proxy객체이다.
그러므로 user의 getName을 호출한다해도 사실은 Proxy객체의 getName을 호출하는것이고
그 안에 영속성 컨텍스트의 "1차 캐시" 에서 값을 가져오는 로직이 작성되어 있는 것이다. - commit이 실행되면 entity manager는 내부적으로 flush()도 동시에 실행함
--> flush()가 실행됐기 때문에 "쓰기 지연 저장소"의 쿼리들이 DB에 실행되고 "1차캐시"는 아직 남아있는 상태
EntityManager em = emf.createEntityManager();
em.getTransation().begin();
User user = new User();
user.setId(1L);
user.setName("myname");
user.setPhone("01012341234");
em.persist(user);
em.flush(); // 코드 추가
em.clear(); // 코드 추가
System.out.println(user.getName());
em.getTransation().commit();
- user 생성 및 영속석 컨텍스트 부여 / "1차 캐시"에 값 저장 / "쓰기 지연 저장소"에 저장되어있는 상태
- em.flush로 "쓰기 지연 저장소"의 쿼리들은 실행시키고 clear로 영속성 컨텍스트 초기화
영속성 컨텍스트의 1차 캐시에 있던 값들도 모두 지워지고 아무것도 없는 상태 - 하지만 user는 아직 proxy객체임
- user.getName() 을 실행시키면 proxy객체의 getName이 실행될것이고 그 안의 작성되있는 "1차 캐시"에서 값을 가져오는 로직이 실행됨
--> 하지만 영속성 컨텍스트자체가 아무것도 없는 상태이고 당연히 "1차 캐시"에서 값을 가져오는것도 불가능한 상태 - LazyInitializationException 발생 : 영속성 컨텍스트가 없는 상태에서 접근하려할때 발생하는 exception
위는 예제를 위한 임시 코드고 보통은 @Transactional 을 통해서 해결하라고 많이 찾아 볼 수 있다.
이유는 일반적으로 @Transactional을 기준으로 영속성 컨텍스트가 구성되기 때문이다.
보통 아래의 경우에 많이 발생하는것 같다.
- @Transactional이 붙어있는 메소드를 이용해서 Entity를 return 받음
--> 영속성 컨텍스트는 이미 비어있지만 return은 Proxy 객체를 return한 상태 - 이 return받은 객체로 안에있는 임의의 값에 참조(사용)함
--> proxy객체를 이용해 영속성 컨텍스트에 접근하려 하지만 아무것도 없는 상태
--> LazyInitializationException 발생
LazyInitializationException은 @Transactional로 해결한다라고 막연하게 알고 있었는데
이렇게 정리해보니 Hibernate의 메커니즘에 대해 더 이해할 수 있게 된다.
반응형
'JPA' 카테고리의 다른 글
Proxy형태로 동작하는 JPA @Transactional (8) | 2021.02.10 |
---|---|
[JPA] OneToOne 성능 튜닝 사례 1 (1) | 2020.08.18 |
JPQL과 영속성 컨텍스트의 관계 (1) | 2020.07.17 |
MultipleBagFetchException과 default_batch_fetch_size (0) | 2020.07.13 |
JPA :: 영속성 컨텍스트 (0) | 2020.07.10 |