Open Session In View
뷰에서도 영속성컨텍스트를 열어놓겠다.
즉, 뷰에서도 지연로딩을 열어놓는다는 뜻이다.
과거OSIV:요청당 트랜잭션
클라에서 요청이 들어오자마자 서블릿필터나 스프링인터셉터에서 트랜잭션을 시작하고 요청이 끝날 때 트랜잭션도 끝내는 것이다.
뷰에서도 지연로딩을 할 수 있게되면서 퍼사드계층없이도 뷰에 독립적인 서비스 계층을 유지할 수 있다.
요청당 트랜잭션의 문제점
(컨트롤러, 뷰)프리젠테이션 계층이 엔티티를 변경할 수 있다.
해결방안
- 엔티티를 read-only 인터페이스로.
- 엔티티 래핑하기
엔티티의 getter(읽기전용메소드)만 있는 래퍼클래스를 만든다.
class MemberWrapper{
private Member member;
public MemberWrapper(member){
this.member = member;
}
public String getName(){
member.getName();
}
}
- DTO만 반환하기
전통적인 방법.
→ BUT, 엔티티를 거의 복사한듯 DTO를 하나더 만들어야함.
현재 스프링OSIV: 비즈니즈계층에서만 트랜잭션유지
spring-orm.jar 에서 다양한 osiv클래스를 제공.

- 클라이언트 요청이 들어오면 서블릿 필터 혹은 스프링 인터셉터에서 영속성 컨텍스트를 생성한다. 단 이때 트랜잭션은 시작하지 않는다.
- 서비스 계층에서 @Transactional로 트랜잭션을 시작할 때 1번에서 미리 생성해둔 영속성 컨텍스트를 찾아와서 트랜잭션을 시작한다.
- 서비스 계층이 끝나면 트랜잭션을 커밋하고 영속성 컨텍스트를 플러시한다. 이때 트랜잭션은 끝내지만 영속성 컨텍스트는 종료하지 않는다.
- 컨트롤러와 뷰까지 영속성 컨텍스트가 유지되므로 조회한 엔티티는 영속 상태를 유지한다.
- 서블릿 필터나 스프링 인터셉터로 요청이 돌아오면 영속성 컨텍스트를 종료한다. 단 이때 플러시를 호출하지 않고 바로 종료한다.
- 영속성 컨텍스트는 트랜잭션없이(범위 밖에서) 엔티티를 조회만 할 수 있다. 이것을 NonTransactional reads라고한다.
서비스에서 컨트롤러로 요청이 넘어간뒤 변경감지(더티체킹)이 안되는 이유
- 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영하려면 영속성 컨텍스트를 플러쉬해야한다. 하지만 트랜잭션을 사용하는 서비스 계층이 끝날 때 트랜잭션이 커밋되면서 이미 플러시해버렸다. 그리고 스프링이 제공하는 osiv 서블릿필터나 osiv스프링인터셉터는 요청이 끝나면 플러시를 호출하지 않고 em.close()로 영속성 컨텍스트만 종료해버리므로 플러시가 일어나지 않는다.
스프링OSIV주의사항
- memberService의 getMember를 통해 찾아온 Member를 영속성 컨텍스트에 저장한다. (트랜잭션은 시작하지 않았지만 영속성 컨텍스트는 존재하기 때문에 가능하다.)
- 찾아온 member의 이름을 XXX로 바꿨다.
- logic() 메소드를 호출하여 트랜잭션이 있는 비즈니스 로직을 실행하였다.
- 트랜잭션 AOP가 동작하면서 영속성 컨텍스트에 트랜잭션을 시작한다. 그리고 logic() 메소드를 실행한다.
- logic()메소드가 끝나면 트랜잭션 AOP는 트랜잭션을 커밋하고 영속성 컨텍스트를 플러시한다. 이때 변경 감지가 동작하면서 회원 엔티티의 수정 사항을 데이터베이스에 반영한다.
- 트랜잭션이 있는 비즈니스로직을 모두 호출하고 나서 엔티티를 변경하면 된다.
단점
- 영속성 컨텍스트와 db커넥션은 1:1로 물고있는 관계이기 때문에 프레젠테이션 로직까지 디비커넥션 리소스를 낭비하게됨.→ 장애로 이어진다.
- osiv를 적용하면 같은 영속성 컨텍스트를 여러 트랜잭션이 공유하기 될 수 있다.
- 프레젠테이션 에서 엔티티를 수정하고 비즈니스 로직수행하면 엔티티가 수정될 수 있다.
- 프레젠테이션 계층에서 렌더링 과정에서 지연 로딩에 의해 SQL이 실행되므로, 성능 튜닝시에 확인해야 할 범위가 넓어진다.