스프링 컨테이너를 이용하여 조회 된 엔티티는 서비스와 리포지토리 계층에서 영속성 컨텍스트에 관리되면서 영속 상태를 유지하지만 컨트롤러나 뷰 같은 프리젠테이션 계층에서는 준영속 상태(트랜잭션이 종료되면서 영속성 컨텍스트도 함께 종료되었기 때문에 준영속 상태로 변환)가 된다.
준영속 상태
변경감지와 지연 로딩이 동작하지 않게된다.
변경감지 : 영속성 컨텍스트가 살아 있는 서비스 계층(트랜잭션 범위)까지만 동작하고 영속성 컨텍스트가 종료된 프리젠테이션 계층에서는 동작하지 않는다.
지연로딩 : 준영속성 상태에서는 지연 로딩 기능이 동작하지 않는다.
그 이유는 바로 준영속성 상태는 영속성 컨텍스트가 없기 때문이다.
해결법 : 뷰가 필요한 엔티티를 미리 로딩해두는법, OSIV를 사용해서 엔티티를 항상 영속 상태로 유지하는 방법
뷰가 필요한 엔티티를 미리 로딩해두는법
글로벌 페치전략 수정 엔티티에 있는 fetch 타입을 지연로딩에서 즉시로딩으로 변경하는 방법.
단점 :
사용하지 않는 엔티티를 로딩한다.
N+1 문제가 발생한다.
JPQL 페치 조인 JPQL 조인 명령어 마지막에 fetch를 넣어주면 된다. 단점 :
무분별하게 사용하면 화면에 맞춘 리포지토리 메소드가 증가한다.
강제로 초기화
영속성 컨텍스트가 살아있을 때 프리젠테이션 계층이 필요한 엔티티를 강제로 초기화해서 반환하는 방법
FACADE 계층 추가
프레젠테이션 계층과 서비스 계층 사이에 FACADE 계층을 하나 더 두는 방법
FACADE 계층의 역할과 특징
프리젠테이션 게층과 도메인 모델 계층 간의 논리적 의존성을 분리
프리젠테이션 계층에서 필요한 프록시 객체를 초기화한다.
서비스 계층을 호출해서 비즈니스 로직을 실행한다.
리포지토리를 직접 호출해서 뷰가 요구하는 엔티티를 찾는다.
OSIV(Open Session In View)
영속성 컨텍스트를 뷰까지 열어준다는 뜻이다.
영속성 컨텍스트가 살아있으면 엔티티는 영속 상태로 유지된다. 즉, 뷰에서도 지연 로딩을 사용 할 수 있다.
스프링 OSIV : 비즈니스 계층 트랜잭션
과거의 OSIV는 모든 계층에서 수정이 가능했다.
하지만 스프링 프레임워크에 와서는 OSIV가 많은 변화가 되었다. 이제부터 무엇이 변화되었는지 보려고 한다.
스프링 프레임워크가 제공하는 OSIV는 비즈니스 계층에서 트랜잭션을 사용하는 OSIV이다.
즉 OSIV를 사용하기는 하지만 트랜잭션은 비즈니스 계층에서만 사용한다는 뜻이다.
클라이언트의 요청이 들어오면 서블릿 필터나, 스프링 인터셉터에서 영속성 컨텍스트를 생성한다. 이때는 트랜잭션은 시작하지는 않는다.
서비스 계층에서 @Transactional로 트랜잭션을 시작할 떄 1번에서 미리 생성해둔 영속성 컨텍스트를 찾아와서 트랜잭션을 시작한다.
서비스 계층이 끝나면 트랜잭션을 커밋하고 영속성 컨텍스트를 플러시한다. 이때 트랜잭션은 끝나지만 영속성 컨텍스트는 종료하지 않는다.
컨트롤러와 뷰까지 영속성 컨텍스트가 유지되므로 조회한 엔티티는 영속 상태를 유지한다.
서블릿 필터나, 스프링 인터셉터로 요청이 돌아오면 영속성 컨테스트를 종료한다. 이때 플러시를 호출하지 않고 바로 종료한다.
즉, 영속성 컨텍스트를 통한 모든 변경은 트랜잭션 안에서 이루어져야 한다. 트랜잭션 없이 엔티티를 변경하고 영속성 컨텍스트를 플러시하면 TransactionRequeiredException 예외가 발생한다.
? 그러면... 그 후에 조회는 어떻게 되는거죠..?
트랜잭션 없이 읽기로 통하여 조회를 한다.
엔티티를 변경하지 않고 단순히 조회만 할 때는 트랜잭션이 없어도 된다.
결과적으로 스프링 OSIV는
영속성 컨텍스트는 트랜잭션 범위 안에서 엔티티를 조회하고 수정.
영속성 컨텍스트는 트랜잭션 범위 밖에서 엔티티를 조회.
트랜잭션 없이 읽기를 사용해서 프리젠테이션 계층에서 지연 로딩 기능을 사용할 수 있다.
프리젠테이션 계층에서 엔티티를 수정할 수 있는 기존 OSIV의 단점을 보완했다.
OSIV 정리
스프링 OSIV의 특징
요청이 끝날 때까지 같은 영속성 컨텍스트를 유지한다.
엔티티 수정은 트랜잭션이 있는 계층에서만 동작한다.
트랜잭션이 없는 프리젠테이션 계층은 지연 로딩을 포함해서 조회만 할 수 있다.
스프링 OSIV의 단점
OSIV를 적용하면 같은 영속성 컨텍스트를 여러 트랜잭션이 공유할 수 있다.
프리젠테이션 계층에서 엔티티를 수정하고나서 비즈니스 로직을 수행하면 엔티티가 수정될 수 있다. (flush)
프리젠티에션 계층에서 지연 로딩에 의한 SQL이 실행된다. 따라서 성능 튜닝시에 확인해야 할 부분이 넓어진다.