OSIV(Open Session In View)는 Hibernate나 JPA와 같은 ORM 프레임워크에서 Lazy Loading으로 데이터를 조회할 때 발생하는 LazyInitializationException 문제를 해결하기 위해 사용하는 패턴입니다. OSIV는 HTTP 요청이 완료될 때까지 Hibernate의 Session 또는 JPA의 EntityManager를 열어둠으로써 Lazy Loading이 가능하도록 지원합니다.
OSIV(open session in view) 는 영속성 컨텍스트를 뷰까지 열어둔다는 의미입니다. 영속성 컨텍스트가 살아있으면 엔티티는 영속 상태로 유지될 수 있어, 뷰에서도 지연 로딩을 사용할 수 있어요. OSIV의 핵심은 뷰에서도 지연 로딩이 가능하도록 하는 것입니다. 가장 단순한 구현은 클라이언트 요청이 들어올때 필터나 인터셉터에서 트랜잭션을 시작하는 방법인데요. 이를 트랜잭션 방식 OSIV라고 합니다. 하지만, 트랜잭션 방식 OSIV는 표현 계층에서도 엔티티를 수정할 수 있기 때문에 유지보수하기 어려운 코드를 만들 수 있습니다.
요청 시작
DispatcherServlet
에서 요청을 처리합니다.Session/EntityManager 열기
Controller/Service 계층 처리
View 계층 처리
Session/EntityManager 닫기
Lazy Loading 지원
구현 편의성
트랜잭션 범위 확장
예측 불가능한 데이터 호출
성능 저하
기본 설정
OSIV 비활성화
application.properties
에서 OSIV를 비활성화할 수 있습니다.spring.jpa.open-in-view=false
Fetch Join 사용
@Query("SELECT u FROM User u JOIN FETCH u.orders WHERE u.id = :id")
Optional<User> findUserWithOrders(@Param("id") Long id);
DTO(Data Transfer Object) 활용
public class UserDTO {
private String name;
private List<String> orders;
public UserDTO(User user) {
this.name = user.getName();
this.orders = user.getOrders().stream()
.map(Order::getProduct)
.collect(Collectors.toList());
}
}
트랜잭션 범위 확장
@Transactional
public User getUser(Long id) {
User user = userRepository.findById(id).orElseThrow();
user.getOrders().size(); // Lazy Loading 강제 초기화
return user;
}
OSIV 활성화 추천
OSIV 비활성화 추천
OSIV는 Lazy Loading 문제를 간편하게 해결해주는 유용한 도구입니다. 그러나 성능과 유지보수 관점에서 신중히 고려해야 합니다. 프로젝트의 요구사항과 환경에 따라 OSIV를 적절히 활성화하거나 비활성화하고, 필요한 경우 Fetch Join, DTO 변환 등의 대체 방식을 활용해야 합니다.
추가 학습 자료