Open Session In View

yeolyeol·2024년 12월 7일
0

til

목록 보기
23/27
post-thumbnail

OSIV(Open Session In View)

1)영속성 컨텍스트를 뷰까지 열어둔다는 의미.
영속성 컨텍스트가 살이있으면 Entity는 영속 상태로 유지될 수 있다. 그래서 뷰에서도 Lazy Loading이 가능하다.
OSIV의 핵심은 뷰에서도 Lazy Loading이 가능하도록 하는 것. 가장 단순한 구현은 클라이언트 요청이 들어올때 Filter나 Interceptor에서 Transaction을 시작하는 방법이다. 그리고 이를 Transaction OSIV 방식이라고 한다.
하지만, 트랜잭션 방식의 OSIV는 표현 계층에서도 Entity를 수정할 수 있기 때문에 유지보수하기 어려운 코드를 야기한다.

짚고 넘어가기 1: 영속성 컨텍스트

일반적으로 Entity의 상태를 관리하는 영역은 Database로 제한되어 있다. 즉, Database에서 꺼낸 Entity를 외부에서 아무리 바꿔도 Database에 반영이 안된다는 것. 그래서 상태가 바뀌면 이를 Database에 저장해 줘야한다.

이후 Database 외부에도 상태를 관리할 수 있는 영역이 나오게 되었는데, 이를 영속성 컨텍스트라고 한다.

영속성 컨텍스트는 Server side와 Database 사이에 Entity를 저장하는 논리적인 영역이라고 할 수 있다. Entity Manager로 Entity를 저장하거나 조회하면 Entity Manager는 영속성 컨테스트에 Entity를 보관하고 관리한다.

그리고 영속성 컨텍스트는 Entity Manager(Session)를 생성할 때 하나 만들어진다. 그리고 Entity Manager(Session)를 통해서 영속성 컨텍스트에 접근할 수 있고 영속성 컨테스트를 관리할 수 있다.

이후, 영속성 컨텍스트와 Lazy Loading에 대해 좀 더 자세하게 다뤄보겠다.

영속성 컨텍스트의 범위를 꼭 늘려야 할까?

영속성 컨텍스트는 Entity Manager가 생성되고 종료되는 시점이라는 생명 주기를 갖고 있다.
즉, @Transactional로 애노테이션이 붙이있는 메서드 영역 내에서만 영속성 컨텍스트를 생성하고 소멸한다.

@Transactional
public Person get(int id) {
		return personRepository.findById(id);
}

그리고 OSIV는 영속성 컨텍스트를 Controller나 View 레이어까지 늘려준다는 것인데, 이렇게 범위를 늘리는 이유를 알아보자.

보통 @Transactional을 사용해서 Service 레이어에서 많이 사용한다. 간혹 Controller나 View 레이어에도 영속성 컨텍스트가 필요한 경우가 있는데, 최근에는 DTO의 사용으로 그런 경험은 하기 힘들다.

컨트롤러 영역에서는 필요한 DTO 모델을 생성하여 DAO에서 내려받은 결과값을 DTO에 바인딩 해주기 때문에 OSIV를 고려해야 하는 경우가 그리 많지 않았을 것이다.
하지만 몇년 전까지만 하더라도 JPA를 사용하면 Dao에서 내려주는 엔티티를 그대로 결과 모델로 사용하는 경우가 많았다. 그러면서 컨트롤러나 뷰 영역에서도 엔티티를 조작하는 경우가 발생하였다.

Spring OSIV

스프링 OSIV는 비즈니스 계층에서만 트랜잭션을 걸어서 사용한다. 그래서 표현 계층에서는 트랜잭션이 없기 때문에 수정이 불가능하다.
하지만, 표현 계층에서 트랜잭션 없는 읽기를 이용해 Lazy Loading이 가능하다.

  1. 클라이언트의 요청이 들어오면 서블릿 필터나 스프링 인터셉터에서 영속성 컨텍스트를 생성한다.
  2. 응용 계층에서 @Transactional로 트랜잭션이 시작할 때 미리 생성한 영속성 컨텍스트를 찾아와서 트랜잭션을 시작한다.
  3. 응용 계층이 끝나면 트랜잭션을 커민하고 영속성 컨텍스트를 flush한다. (이때, 영속성 컨텍스트는 종료하지 않는다.)
  4. 컨트롤러와 뷰까지 영속성 컨텍스트가 유지되기 때문에 조회한 엔티티는 영속 상태를 유지할 수 있다.
  5. 필터, 인터셉터로 요청이 돌아오면 영속성 컨텍스트를 종료한다. (이때 flush는 수행하지 않는다.)

문제점

  • 표현 계층에서 엔티티를 수정하면 Database에 반영되지 않는다. 하지만, 엔티티를 수정한 이후 트랜잭션을 시작하는 응용 계층이 수행한다면 문제가 발생할 수 있다.
    응용 계층 트랜잭션이 끝나고 영속성 컨텍스트를 flush하는 과정에서 변경 감지가 동작할 수 있기 때문이다.
  • OSIV 기능을 사용하면 상대적으로 오래 Database Connection을 점유한다. 그래서 Connection 고갈로 이어질 수 있기 때문에, 대규모 트래픽에 비용이 많이 든다.

해결?

그럼 그냥 안쓰면 해결되는 문제가 아닌가? 싶을 수 있다.
무조건 비활성화하기 보다는 비활성화하려는 근거가 필요하다. 만약, 트랜잭션 범위 밖에서 Lazy Loading을 반드시 수행해야 하는 경우에는 비활성화가 어렵다.

반대로, 대량의 트래픽이 발생하는 경우에는 Database Connection을 효율적으로 사용해야한다. 이러한 경우에는 OSIV 비활성화를 고려해볼 필요가 있다.

결론

즉, OSIV 기능을 명확하게 알고 상황에 맞게 활성화 / 비활성화를 적절히 사용하는 것이 정답이라고 생각한다.

참고자료

profile
한 걸음씩 꾸준히

0개의 댓글

관련 채용 정보