| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 서버리스 #
- font-size
- 10px
- 데이터베이스 #try #이중
- 으
- 0.75px border
- angular
- 타입스크립트
- &연산
- 문서번호
- Props
- github
- npm
- 클론코딩
- literal
- TS
- ZOOM
- 1px border
- 전역변수
- Websocket
- 당근마켓
- TypeScript
- es6
- ES5
- entity
- Strict
- 0.5px border
- jwt
- 컴포넌튼
- 0.25px border
- Today
- Total
복잡한뇌구조마냥
[JPA] OSIV ( Open Session In View ) 본문
1️⃣ OSIV(Open Session In View) 개념 잡기
✔ OSIV / OEIV 용어 정리
| 용어 | 설명 |
| OSIV (Open Session In View) | Hibernate 환경에서 Session을 요청–응답 전 범위에서 열어두는 패턴 |
| OEIV (Open EntityManager In View) | JPA 환경에서 EntityManager를 요청–응답 범위에서 유지하는 패턴 |
둘은 실질적으로 동일하며, 관례적으로 OSIV라고 부른다.
👉 핵심 개념
요청(Request) 시작부터 응답(Response)까지 영속성 컨텍스트를 열어둔다.
→ 트랜잭션이 끝난 뒤에도 Lazy Loading이 가능해진다.
2️⃣ OSIV의 동작 방식
OSIV가 true일 때 JPA의 동작 흐름은 다음과 같다:
[요청(Request) 시작]
↓
OSIV Filter가 영속성 컨텍스트(EntityManager) 생성
↓
Service 계층(@Transactional) 수행 후 트랜잭션 종료
(하지만 EntityManager는 닫히지 않음)
↓
Controller / View / JSON 직렬화 과정에서도 Lazy 로딩 가능
↓
응답(Response) 직전에 EntityManager 종료
✔ 스프링 설정
spring:
jpa:
open-in-view: false # 기본값 true, OSIV 활성화
3️⃣ OSIV를 사용하면 좋은 이유 (장점)
✔ 1) Lazy Loading을 마음껏 사용할 수 있다
OSIV = true일 경우:
- Service layer에서 트랜잭션이 끝났더라도
- Controller/JSON 변환 과정에서 .getOrders()처럼 LAZY 필드를 접근하면
- Hibernate가 즉시 DB 쿼리를 날려 데이터를 가져온다
→ 개발할 때 매우 “편하다”.
✔ 2) DTO 변환 없이 엔티티를 반환하는 코드 스타일이 가능
OSIV가 켜져 있으면:
- 엔티티를 Controller까지 그대로 넘겨도 문제 없음
- Jackson 직렬화 과정에서 Lazy 필드를 호출해 쿼리가 나간다
- 개발 난이도 ↓, 코드 간결
즉, 개발 속도가 빨라지는 구조이다.
4️⃣ OSIV가 갖는 치명적인 단점 — 성능 폭탄
OSIV가 true일 때 가장 위험한 점은 다음이다.
❌ “트랜잭션은 끝났는데, DB 커넥션은 계속 점유한다”
즉:
- OSIV는 영속성 컨텍스트를 Request 전체에 걸쳐 유지한다
- 영속성 컨텍스트는 내부적으로 DB Connection을 붙잡고 있는 경우가 많다
→ 외부 API 호출, 연산, 랜더링 등 JPA와 무관한 시간에도
→ DB 커넥션을 계속 유지한다.
영상에서 나온 사례:
🔥 예시 — 외부 API 호출이 15초 걸리는 경우
| OSIV = true | OSIV = false |
| 15초 동안 DB 커넥션 점유 | 트랜잭션 종료 → 커넥션 반환 |
| Connection Pool 고갈 가능 | 외부 API 시간 동안 DB 부하 없음 |
| 트래픽 많은 서비스에서 장애 유발 | 안정적 운영 가능 |
즉, OSIV는 개발자가 생각하는 것보다 훨씬 위험하다.
5️⃣ OSIV ON/OFF 비교
| 항목 | OSIV = true | OSIV = false |
| Lazy Loading 시점 | Controller/Response까지 가능 | 오직 트랜잭션 내부에서만 가능 |
| LazyInitializationException | 거의 없음 | 서비스 밖에서 Lazy 접근 시 즉시 발생 |
| 개발 난이도 | 쉽고 빠름 | DTO/FetchJoin 필요 |
| DB Connection 점유 | 길어짐 (심각) | 짧음 |
| 성능 이슈 | 발생 확률 높음 | 안정적 |
| 구조적 장점 | Layered Architecture 흐트러짐 | 계층 분리 명확 |
| 운영 적합성 | ❌ 낮음 | ⭕ 높음 |
6️⃣ 많은 전문가들이 OSIV를 "안티 패턴"이라고 부르는 이유
- 성능 이슈가 발생하기 쉽고
- 계층 구조가 깨지고
- 엔티티가 Controller/JSON 변환에 노출된다는 점 때문에
Hibernate Community에서도 여러 차례 경고가 있었고
국내·해외 개발자들 대부분은 운영 환경에서는 OSIV를 끌 것을 권장한다.
→ 즉, OSIV는 “편한 기능이지만 위험한 기능”.
7️⃣ 결론 — OSIV는 언제 켜야 하고, 언제 꺼야 할까?
✔ OSIV = true (허용되는 경우)
- 트래픽 적은 내부 어드민
- Lazy 로딩을 템플릿 기반 웹 뷰에서 많이 활용할 때
- 개발 속도를 중요시하는 초기 단계
→ 성능보다는 편의성을 우선하는 환경
✔ OSIV = false (권장)
- 트래픽이 많은 B2C 서비스
- API 서버 (특히 REST API)
- 외부 연동이 많은 서비스
- 대량 처리/배치가 있는 시스템
- 장애 발생 시 피해 규모가 큰 서비스
→ 대부분의 현대 서비스 구조에서는 false가 정석
8️⃣ OSIV = false일 때 필요한 전략
OSIV를 끄면 Lazy Loading이 트랜잭션 밖에서 동작하지 않기 때문에
다양한 설계 전략이 필요하다.
🔹 1) Fetch Join 적극 활용
Lazy 필드를 미리 한번에 가져오기
🔹 2) DTO 변환을 Service 계층에서 수행
Controller까지 엔티티가 노출되지 않게 하기
🔹 3) QueryDSL 또는 JOOQ 사용
복잡한 조회는 전용 Query layer에서 해결
🔹 4) CQRS 구조 적용
Command(JPA) / Query(QueryDSL·JOOQ) 분리
→ OSIV를 끄는 순간 구조가 “올바른 방향”으로 강제되는 효과가 있다.
📌 최종 요약
OSIV는 개발 속도를 높이기 위해 만들어진 기능이지만,
운영 환경에서 성능 문제(DB 커넥션 고갈)를 야기할 수 있기 때문에
대부분의 서비스에서는 OSIV = false로 설정하는 것이 정답에 가깝다.
참고자료:
https://www.youtube.com/watch?v=Q2n9I86mav4
'BE > Spring' 카테고리의 다른 글
| [Spring] SMTP 기반 메일 인증 ( + 비동기 처리 ) (0) | 2025.11.30 |
|---|---|
| [Spring] Spring Batch + Scheduler 정리 (0) | 2025.11.27 |
| [Spring] JOOQ ( + QueryDSL vs JOOQ ) (0) | 2025.11.21 |
| [Spring] Spring AI ( OpenAI + Rag + MariaDB Vector ) (0) | 2025.11.18 |
| [Spring] Spring Security + OAuth2 로그인 (0) | 2025.10.15 |