본문 바로가기

JPA

[JPA] SpringDataJPA - OSIV

[JPA] SpringDataJPA - OSIV and etc..

지연로딩으로 인해 프록시 객체가 들어있는 엔티티를 트랜잭션 범위 밖에서 초기화 하려고하면 에러가 발생한다. 스프링에서는 이런 문제를 해결하기위해, OSIV라는 방법을 제공하는데, 그 전에, API를 사용하지않고, 해결하는 방법을 알아보자.

미리 초기화, Facade, DTO만 넘기기

첫번째 해결법은 트랜잭션 범위가 끝나기전에 엔티티를 미리 초기화 하는 것 이다. 

 

이 방법은 관리해야할 트랜잭션 범위가 OSIV보다 적어서 디버깅이 편하지만, 코드량이 늘어나는 단점이 있다.

또한, 뷰에 맞는 최적화 코드를 추가로 생성해야 하므로, 코드끼리의 논리적인 의존도가 증가할수있다.

 

예를들어,

뷰 A는 user1엔티티만 필요하고, 뷰 B는 user1엔티티와 user1의 parent엔티티가 필요하다 이 때, 뷰 B를 위해 뷰 A에 user1+parent엔티티까지 초기화 하여 넘기는것은 비효율적이다. 따라서, 최적화시 뷰A와 뷰B에 맞는 최적화 메소드가 추가로 필요하게 되고, 이는 논리적인 의존도의 증가로 이어진다.

 

OSIV(Open Session In View)

스프링에서는 OSIV라는 것을 제공하여 지연로딩의 문제점을 해결한다.

OSIV는 엔티티 매니저를 뷰 레이어 까지 열어두어 엔티티 매니저의 지연로딩, 혹은 조회를 가능하게 하고, 수정은 막는 기법이다.

 

OSIV의 동작원리는 다음과 같다.

1. 서블릿 필터 혹은 인터셉터에 OSIV를 적용한다. 

 

2. OSIV를 거쳐오며 엔티티 매니저가 생성되고 열린 상태로 클라이언트의 요청이 도착한다.

 

3. 트랜잭션이 시작되는 레이어에서 이전에 생성된 엔티티 매니저를 가져와 사용한다.

 

4. 트랜잭션이 종료되고, 지연로딩된 엔티티가 뷰 레이어에 반환된다.

 

5. 이때, 뷰 레이어에서는 지연로딩된 엔티티를 초기화 하려한다. 트랜잭션은 종료되었지만, 엔티티 매니저는 열려있으므로, 지연로딩된 엔티티 초기화가 성공한다.

이것을 트랜잭션없는 읽기 라고하는데 트랜잭션이 없다면, 엔티티 매니저를 수정하지않고, 조회만 하는것은 가능하다.

 

6. 요청이 끝나면, 엔티티 매니저를 종료한다. 단, 이때 플러시는 하지 않는다.

플러시를 하지않기때문에, 뷰 레이어에서 엔티티의 변경은 반영되지 않는다.

 

OSIV는 증가되는 코드량도 적고, 실용적이지만, 뷰에서 엔티티를 변경한후 다시 트랜잭션을 시작하면 예기치못한 오류가 발생할수있다.

위의 2,3번을 보자. Spring은 일반적으로, 하나의 트랜잭션에 하나의 엔티티 매니저를 사용하지만, OSIV를 사용할 경우 이전에 만들었던 엔티티 매니저를 그대로 가져와 사용한다. 따라서, 뷰에서 엔티티를 변경한후 다시 트랜잭션을 시작하면, 엔티티의 변경이 DB에 그대로 저장되게 된다.

 

OSIV방식은 엔티티 매니저를 뷰 까지 열어두게 되어, 도메인 레이어에 신경쓰지 않고, 로직 개발에 집중할수있다. 하지만, 이 때문에, DB리소스를 상대적으로 더 잡아먹는 단점이 있다. 

또한, 뷰에서 초기화 시점에 발생하는 SQL문 으로 인해 성능 튜닝시 신경써야하는 부분이 늘어난다.

'JPA' 카테고리의 다른 글

[JPA] 지연로딩과 영속성전이  (0) 2021.10.23
[JPA] 고급 매핑 - 상속 관계, 복합키와 식별 관계  (0) 2021.10.17
[JPA] 연관관계 매핑  (0) 2021.10.14
[JPA] 필드와 컬럼 매핑  (0) 2021.10.12
[JPA] JPA 영속성 컨텍스트  (0) 2021.10.11