컬렉션 조회(OneToMany) 최적화
Fetch Join의 한계
- 2개 이상의 컬렉션 fetch join이 불가능하다. 컬렉션 페치 조인은 1개만 사용할 수 있다. 2개 이상의 컬렉션을 fetch join하게 된다면, 카테시안 곱으로 처리하기 때문에 너무 많은 값이 메모리로 들어와 MultipleBagFetchException이 발생하게 된다.
- 컬렉션 fetch join일 경우, 페이징이 불가능하다. 조인 시에 ‘多’ 엔티티의 데이터 개수에 맞추어 데이터가 중복되어 생성되기 때문에 페이징 기준이 틀어져 페이징이 불가능하다. 엄밀히 말하면, 가능하지만 절대 페이징 처리를 해서는 안된다. 컬렉션 페치 조인 시 페이징처리를 하게 되면, 하이버네이트는 경고 로그를 남기면서 모든 데이터를 DB에서 읽어오고 메모리에서 페이징을 처리하기 때문이다.
OSIV 전략
OSIV는 Open Session In View의 약자로 최초 데이터베이스 커넥션 시작 시점부터 API 응답이 끝날 때까지 영속성 컨텍스트와 데이터베이스 커넥션을 유지하는 전략이다.
OSIV ON
지연 로딩의 경우, 영속성 컨텍스트가 살아있어야 초기화가 가능하고 이러한 영속성 컨텍스트는 기본적으로 데이터베이스 커넥션을 유지한다. 때문에 OSIV 전략을 사용하면, View Template이나 API 컨트롤러에서도 지연로딩 초기화가 가능했었던 것이다. 하지만, 이러한 전략은 너무 오랜시간동안 데이터베이스 커넥션 리소스를 사용하기 때문에, 실시간 트래픽이 중요한 애플리케이션에서는 커넥션이 모자랄 수 있다.
OSIV OFF
OSIV 전략을 사용하지 않으면, 트랜잭션을 종료할 때 영속성 컨텍스트를 닫고 데이터 커넥션도 반환한다. 따라서 리소스를 낭비하지 않는다는 이점이 있다. spring.jpa.open-in-view:false 설정을 통해 OSIV를 종료할 수 있다. 하지만 OSIV를 끄면 모든 지연로딩을 트랜잭션 안에서 처리해야 한다는 단점이 있다. 즉, 많은 지연 로딩 관련 코드들을 트랜잭션 안으로 넣어야 한다는 것이다. 그렇지 않을 경우, LazyInitializationException 오류가 발생하게 된다. 결론적으로, OSIV 전략을 사용하지 않으면, 트랜잭션이 끝나기 전에 Fetch Join을 활용하거나 Command와 Query를 분리하는 등의 방법을 통해 지연로딩을 강제로 호출해주어야 한다.
'JPA' 카테고리의 다른 글
실전! 스프링 데이터 JPA - 섹션 6~8 (0) | 2025.03.17 |
---|---|
실전! 스프링 데이터 JPA - 섹션 1~5 (0) | 2025.03.17 |
실전! 스프링 부트와 JPA 활용 2 - 섹션 1~4 (0) | 2025.03.17 |
실전! 스프링 부트와 JPA 활용1 - 섹션 3~7 (0) | 2025.03.17 |
실전! 스프링 부트와 JPA 활용1 - 섹션 1~2 (0) | 2025.03.17 |