Open Session In View. 영속성 컨텍스트(와 DB 커넥션)를 컨트롤러·뷰 렌더링까지 열어 두는 설정. Spring Boot에서 기본이 켜져 있다.
무엇을 해결하나
@Transactional
Order find(Long id) { return repo.findById(id).orElseThrow(); }
// 컨트롤러에서
Order o = service.find(1L);
o.getMember().getName(); // 트랜잭션은 끝났다
OSIV 꺼짐 → LazyInitializationException: could not initialize proxy - no Session OSIV 켜짐 → 컨텍스트가 아직 살아 있어 지연 로딩이 동작한다
대가 — 커넥션을 오래 쥔다
[OSIV ON]
요청 시작 ──── 커넥션 확보 ──── 서비스 ──── 컨트롤러 ──── 뷰 렌더링 ──── 커넥션 반납
└──────────────── 이 구간 내내 커넥션 점유 ────────────────┘
[OSIV OFF]
요청 시작 ─── 서비스(트랜잭션) ─── 반납 ─── 컨트롤러 ─── 뷰 렌더링
└─ 이 구간만 점유 ─┘
외부 API 호출이나 느린 렌더링이 컨트롤러에 있으면, 그동안 커넥션이 묶인다. 트래픽이 몰리면 커넥션 풀이 마르고 전체 서비스가 멈춘다.
끄는 법과 그 대가
spring:
jpa:
open-in-view: false # 끄면 기동 시 WARN 로그가 사라진다
끄면 지연 로딩을 트랜잭션 안에서 끝내야 한다.
// ① 페치 조인으로 필요한 걸 다 가져온다
@Query("select o from Order o join fetch o.member where o.id = :id")
Order findWithMember(@Param("id") Long id);
// ② 트랜잭션 안에서 DTO 로 변환해 내보낸다 (권장)
@Transactional(readOnly = true)
OrderDto find(Long id) {
Order o = repo.findById(id).orElseThrow();
return new OrderDto(o.getId(), o.getMember().getName()); // 여기서 초기화된다
}
②가 정석이다 — 엔티티를 계층 밖으로 내보내지 않으면 OSIV도 LazyInitializationException도 문제가 되지 않는다.
어떻게 판단하나
- 트래픽이 적은 사내 시스템 · 빠른 개발이 우선 — → 켜 둬도 된다
- 외부 API 호출이 섞인다 · 트래픽이 많다 — → 끄고 DTO 변환으로 간다
Spring Boot가 기동할 때 이 설정에 대해 WARN을 찍는 이유가 "기본값이지만 의식적으로 정하라"는 신호다.
면접 함정
- ❌ "OSIV를 끄면 성능이 좋아진다" → 커넥션 점유 시간이 줄 뿐, 쿼리 자체가 빨라지지 않는다.
- ❌ "OSIV가 켜져 있으면 트랜잭션도 열려 있다" → 컨텍스트만 열려 있다. 트랜잭션은 서비스에서 끝나므로 컨트롤러의 변경은 반영되지 않는다.
켜져 있는지 확인하는 법
기동 로그에 이 경고가 있으면 켜져 있는 것이다
spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
"명시적으로 정하라" 는 뜻이다. 끄든 켜든 설정 파일에 적어 두는 것이 의도를 남기는 방법이다.
끄면 어디서 터지나
// 컨트롤러에서 엔티티를 그대로 반환하면 직렬화 중에 터진다
@GetMapping("/orders/{id}")
public Order get(@PathVariable Long id) { return service.find(id); }
// LazyInitializationException: could not initialize proxy - no Session
// ← Jackson 이 getMember() 를 부르는 순간
엔티티를 API 응답으로 내보내지 않는 것이 근본 해법이다. DTO로 바꾸면 OSIV 설정과 무관해지고, 스키마 변경이 API에 새는 것도 막힌다.
// Jackson 이 프록시를 만나 터지는 것 자체를 막는 모듈도 있다
// Hibernate5Module — 초기화 안 된 프록시를 null 로 직렬화한다 (임시방편)