250x250
Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- 최소힙
- 연결리스트
- 운영체제
- AVL트리
- MSA
- 연결리스트 종류
- 알고리즘
- 최대 힙
- 스케줄링
- 백준 장학금
- 완전이진트리
- 백준장학금
- 자료구조
- 멀티프로세서
- 힙트리
- 강화학습
- 이분탐색이란
- 점근적 표기법
- Kruskal
- heapq
- JVM
- python
- HTTP
- JPA
- SpringSecurity
- 엔티티 그래프
- 프로세스
- posix
- spring
- jpa n+1 문제
Archives
- Today
- Total
KKanging
[JPA] Context 주기와 트랜잭션 주기 그리고 OSIV 본문
스프링의 @Transactional 어노테이션과 트랜잭션 범위
- 스프링의 Service 계층에 @Transactional 어노테이션을 많이 봤을 것이다.
- 스프링의 @Transactional 어노테이션은 AOP로 구현되었으며, 메소드 시작할때 영속성 컨텍스트와 트랜잭션을 시작한다.
- 대상 메소드가 종료하면 트랜잭션을 커밋하고 종료한다.
- 트랜잭션을 종료하면 영속성 컨텍스트도 종료하고 같은 트랜잭션에는 같은 영속성 컨텍스트를 사용한다.
- 트랜잭션을 커밋하면 컨텍스트를 플러시하고 변경 내용을 데배에 반영한다.
- 그리고 데이터베이스의 트랜잭션을 커밋한다.
- 따라서 영속성 컨텍스트의 변경 내용이 데이터베이스에 정상 반영된다.
- 만약 트랜잭션의 예외가 발생하면 트랜잭션을 종료하는데 이때는 플러시를 하지 않는다.
요약
스프링의 트랜잭션 어노테이션은 -> AOP로 구현됨
트랜잭션의 주기와 영속성 컨텍스트의 생존 주기가 같음
같은 트랜잭션이면 같은 영속성 컨텍스트의 접근함
만약 준영속 상태에서 지연로딩 문제를 해결하기 위해선?
문제점
- 준영속 상태의 엔티티를 지연로딩으로 연관 엔티티를 조회하거나
- 변경을 하게 된다면 감지를 못해서 에러가 나거나 원하는 결과를 가질 수 없다.
해결방법
- 영속성 컨텍스트가 종료되기 전에 즉시 로딩
- 글로벌 패치 전략 수정(지연 → 즉시)
- JPQL 페치 조인
- 강제로 초기화
- FACADE 계층 추가
- OSIV를 사용하여 엔티티를 항상 영속 상태로 유지
글로벌 패치 전략
- 지연로딩을 → 즉시로딩으로 수정함으로써 엔티티를 로딩할 때 바로 로딩되게끔
- 문제점
- 유연하지 못한 로딩 전략
- 다른 코드에서는 연관 엔티티를 사용안 할수도 있음
- N+1 문제
- 유연하지 못한 로딩 전략
JPQL 페치 조인
- 가장 많이 쓰는거 같음
- 한번의 쿼리로 연관된 엔티티 한번의 조회
- JPQL 페치 조인으로 N+1 문제 해결
- 문제점
- 엔티티 종류마다 메소드를 만들어서 repository 의존도가 상승할 수 있음
강제로 초기화
- 지연로딩인 엔티티를 강제로 초기화 하여 로딩되게 함
- 문제점
- 글로벌 패치 전략과 동일
- 코드가 지저분해질 수도?
FACADE 계층 추가
- 위에 강제로 초기화 처럼 엔티티를 초기화하는 코드를 사용하다보면 Service 계층의 역할이 SRP 이 잘 구현하기 힘들다
- 그래서 엔티티를 초기화하는 Facade 계층을 추가하는 방법이 있다.
- 하지만 이는 코드의 역할 분리에는 좋지만 코드가 증가하고 계층에 분리로 인한 가독성이 떨어질 수 있다.
OSIV (Open Session In View)
- JPA에서는 OEIV 라고 부르기도 한다(OSIV는 하이버네이트에서 부른다)
- OSIV의 목적은 영속성 컨텍스트를 프레젠테이션 계층까지 열어두는 것이다.
- 즉, Service → Repository 계층에만 국한되어 있지않게 끔 하는 것
과거 OSIV: 요청 당 트랜잭션
- 과거 OSIV 는 요청당 스레드를 할당하면서 영속성 컨텍스트와 트랜잭션를 생성했다.
- 따라서 Transaction per Request라고 부르기도 한다.
- 문제점
- 프레젠테이션 계층에서 엔티티 변경 위험
- 엔티티 변경을 위한 해결방안
- 엔티티를 읽기 전용 인터페이스로 제공
- 엔티티 레핑
- DTO만 반환
- 하지만 위와 같은 해결방안은 해결방안이지만 해결하기 위한 부수적인 요소가 많아 사실상 과거 OSIV 는 안좋은 요소가 많다.
- 엔티티 변경을 위한 해결방안
- 프레젠테이션 계층에서 엔티티 변경 위험
스프링 OSIV: 비즈니스 계층 트랜잭션
- 사용자의 요청에 영속성 컨텍스트를 생성한다.
- 그리고 트랜잭션을 생성 ~ 종료 와 영속성 컨텍스트의 생존과는 무관하다.
- 요청이 끝날 때 영속성 컨텍스트를 종료한다.
- 특징
- 영속성 컨텍스트를 프리젠테이션 계층까지 유지한다.
- 프리젠테이션 계층에는 트랜잭션이 없으므로 엔티티를 수정할 수 없다.
- 프리젠테이션 계층에는 트랜잭션 없이 읽기를 사용해서 지연 로딩을 할 수 있다.
트랜잭션 없이 읽기
- 영속성 컨텍스트의 주기는 요청의 주기와 같은데, 이 때 지연로딩이 트랜잭션 없이도 가능하다.
- 업데이트나 저장 같은 쿼리는 트랜잭션이 필요하다 하지만, 읽기 같은 조회는 트랜잭션 없이도 가능하기 때문에 가능하다!
주의 사항
- OSIV를 사용하면 영속성 컨텍스트는 요청의 주기와 같다
- 그렇다는 건 DataSource를 요청이 처리할 동안 쓰기 때문에 요청이 많은 서비스이면 장애가 발생하기 쉽다.
- DB 접근을 안하는 요청에도 자원을 쓸것 같아서 흠… 쓰기 애매한거 같다.
사용법
spring.jpa.open-in-view:true #디폴트 세팅
사용하지 않을 때는 false로 해두어야 한다.
참고자료
- >자바 ORM 표준 JPA 프로그래밍 - 김영한
'백엔드 > JPA' 카테고리의 다른 글
[JPA] JPA N+1 문제 발생 원인과 해결 방법 (0) | 2024.05.14 |
---|---|
[JPA] 엔티티 그래프 (0) | 2024.05.10 |