OSIV(Open Session In View)에 대한 글
선수 지식 - EntityManager
EntityManager는 애플리케이션에서 영속성컨텍스트에 접근할 수 있도록 하는 객체이다.
데이터베이스 연결이 필요한 시점까지 커넥션을 얻지 않으며, 데이터를 변경(Write)시에는 트랜잭선을 시작해야한다.
스프링은 요청마다 EntityManager를 EntityManagerFactory를 통해서 생성한다.
선수 지식 - @Transactional이 붙은 메소드가 실행되는 로직
- db connection pool에서 현재 thread에서 사용할 db connection을 가져온다.
- db connection을 EntityManager에 바인딩한다.
- database operation를 수행한다.
- database operation를 수행한 결과를 바탕으로 EntityManager는 영속성 컨텍스트를 관리한다.
- exception이 발생하면 롤백한다.
- exception이 발생하지 않았다면, 커밋한다.
- 커밋이 완료되면 사용했던 db connection을 반납하고, EntityManager를 닫고 영속성 컨텍스트 역시 삭제된다.
OSIV란?
JPA에서는 OEIV(Open EntityManager In View)로,
EntityManager를 View단 까지 열어놓는다라는 의미이다. 조금 더 자세히 설명해보면,
OSIV - Off
OSIV - Off 선수 지식의 @Transactional 내용과 일치하는 그림이다. 트랜잭션이 종료되고나면, 영속성 컨텍스트와 db connection 모두 사라진다.
OSIV - On
OSIV - On 트랜잭션이 종료되더라도, 계속해서 EntityManager, 영속성 컨텍스트, db connection를 유지하면서 Controller, View단에서 영속성컨텍스트를 사용할 수 있다.
OSIV - 장점
OSIV를 사용하면 트랜잭션이 종료되어도 영속성 컨텍스트와 db connection이 계속 유지되기떄문에, Controller, View 단에서 지연로딩(Lazy Loading)이 가능하다. Lazy Loading은 개발자가 LazyInitializationException을 신경쓰지 않고 쉽게 개발할 수 있게해준다는 장점이 있다.
OSIV - 단점
LazyInitializationException을 신경쓰지 않아도되지만, 성능상 아주 큰 단점이 있다.
LazyLoading으로 인해서 예상하지 못한 불필요한 쿼리문이 발생될 수 있다.
db connection을 반납하지 않기때문에 해당 요청 시작에서 응답이 나갈 때까지 db connection을 소유하고 있는다.
기본적으로 db connection을 비효율적으로 사용하게 되는 것이고, 해당 요청 로직내에서 외부 api를 호출하는 작업이 있어서 더 응답시간이 길어지는 경우에는 더욱 더 db connection을 낭비하게 된다.
전략
OSIV는 지양하자
일반적으로 스프링으로 웹 애플리케이션을 개발한다고 하면 데이터베이스와 통신하면서 CRUD를 하는 경우가 대부분이기 떄문에, 많은 사용자가 있는 경우 OSIV를 사용하지 않는 것이 좋다.
OSIV를 사용하지 않으면 LazyLoading이 불가하기떄문에 트랜잭션내에서 적절한 쿼리문으로 데이터를 가져와야므로 쿼리 최적화를 한다거나 하는 작업이 필요하다.
JPA와 같은 ORM을 사용하면서 추상화된 메소드만을 사용해서는 적절한 쿼리문(내가 원하는 데이터를 가져오면서 최적화된 쿼리)을 사용하기엔 무리가 있다. 따라서 SQL과 JPA에 대한 깊은 학습과 활용법에 대한 공부가 필요하다.
CQRS로 복잡성을 관리하자
OSIV를 사용했을 때의 단점을 해결해주는 것이아니라 OSIV를 사용하지 않을때 생길 수 있는 단점을 다루는 방법 중 하나이다.
OSIV를 사용하지 않는 경우, LazyLoading이 불가능하고, 그에 따라서 조회 관련된 메소드가 수많이 파생될 수 있다.
예를 들면 LazyLoading이 되는 상황이면, 단순히 JPAReposository에서 find를 통해서 Entity 객체를 가져오고 그 Entity 객체를 통해서 원하는 데이터를 뽑아서 응답을 만들면되지만,
LazyLoading이 안되면 최적화된 쿼리마다 메소드가 존재할 것이기 떄문이다.
OSIV 성능 이슈보다는, 이렇게 요구사항이 복잡해지는 상황에서 CQRS(Command Query Responsibility Separation)패턴을 적용해서 관심사를 나눠서 관리할 수 있다라는 것이다.
Refercence
- 자바 ORM 표준 JPA 프로그래밍 - 김영한