본문 바로가기
프로젝트

지연 로딩(Lazy loading), 영속성 컨텍스트

by backwards 2023. 6. 18.

 

요약

지연 로딩을 사용하면 실제객체 대신 proxy객체를 넣어둔다.

실제 데이터가 필요한 순간 DB를 조회하여 proxy객체를 초기화하는데, 영속성 컨텍스트가 종료되어 준영속 상태가 되었기 때문에 문제가 발생했다.

트랜잭션을 적절히 적용하여 문제를 해결하였다.

 


 

 

문제점

member엔티티와 conversation엔티티는 1:N 관계이고, 지연 로딩으로 설정되어있다.

 

지금까지 지연로딩에 대해 알고 있었던 사실은

conversation을 불러올 때 member proxy객체를 불러오고, 실제 member객체를 조회할 때 비로소 select쿼리를 실행한다는 것이다.

 

영속성 컨텍스트의 상태에 대해서는 알지 못했고, 이 부분이 문제가 되었다. 

 


영속성 컨텍스트

JPA에서 엔티티를 DB에 저장할 때 영속성 컨텍스트를 거친다.

그림을 간단하게 그려보면 다음과 같다.


분석

정확히 어떤 문제인지 위의 영속성 컨텍스트 그림을 기반으로 설명해보겠다.

 

1. 모든 conversation 조회

find() 메서드 실행 시 영속성 컨텍스트의 1차 캐시를 조회하는데, 1차 캐시에 엔티티가 없으면 엔티티 매니저는 DB를 조회해서 엔티티를 생성한다. 그리고 1차캐시에 저장한 후 영속 상태의 엔티티를 반환한다.

 

2. 엔티티 to DTO

이 부분에서 문제가 발생한다.

조회 메서드와 엔티티toDTO 메서드가 한 트랜잭션으로 묶여있지 않다. 

조회 메서드가 끝난 후 트랜잭션이 종료되고 영속성 컨텍스트도 종료되어 준영속 상태가 된다.

 

해당 상황에서 conversation엔티티를 DTO로 매핑하기 위해 member엔티티에 접근하게 되면 당연히 문제가 발생한다.

현재 conversation엔티티에는 지연로딩으로 인해 proxy member객체만 존재하는 상태이고 영속성 컨텍스트가 실제 객체를 더이상 관리하지 않기 때문이다.

 


해결 방법

DTO로 매핑되기 까지 영속성 컨텍스트가 종료되지 않도록 위의 두개의 메서드를 @Transactional을 이용해 하나의 트랜잭션으로 묶어주었다. 

FetchType을 즉시로딩으로 바꿔주는 방법도 있으나 다른 요청에서 원치않은 쿼리문이 실행될 수 있으므로 이 방법은 사용하지 않았다.

 

 

 

 


참고: 김영한. 『자바 ORM 표준 JPA 프로그래밍』

'프로젝트' 카테고리의 다른 글

JPA n+1 문제  (0) 2023.06.21
대화방 제목/pin 수정 - fetchType과 DTO  (0) 2023.06.14
대화방 생성 - 중복된 sql 쿼리문  (0) 2023.06.12
프로젝트 개선  (0) 2023.06.09