스프링 이론을, 특히 트랜잭션과 관련한 내용을 살펴보면서 의문이 생겼다.
- 영속성 컨텍스트는 Transaction 단위로 관리된다. 즉, 트랜잭션이 종료되면 영속성 컨텍스트는 소멸한다.
- 만약 Service 계층에서, @Transactional을 붙인 메소드를 호출한다면 트랜잭션은 Service의 메소드가 종료 될 때 함께 종료된다.
- 그렇다면, 컨트롤러에서 Service 계층의 메소드를 호출해 엔티티를 받았다면, 그 때는 트랜잭션이 끝난 상태이다.
- 해당 엔티티는 "Detached". 즉 영속성 컨텍스트의 관리를 받지 않는다
- Detached 상태 엔티티는 DB와 연결 매개체가 없으므로, Lazy-Loading을 사용 할 수 없다.
- 그렇다면 컨트롤러에선 Lazy-Loading 필드에 접근 할 수 없..다?
위와 같은 흐름을 통해 의문이 생겼는데, 그러면 컨트롤러와 뷰는 Lazy-Load를 쓸 수 없는건가?
AOP를 통해 메소드의 시작/종료에 로그를 찍게 했다. 보면 Service 및 Controller까지 종료되었고, 타임리프를 통해 뷰를 그렸다.
이후 타임리프에서, Lazy-load로 설정된 필드를 접근했는데...!! (일부러 N+1 문제를 발생시켰다.)
쿼리가 나간다.
뭐지? 분명 트랜잭션도 끝났고 영속성 컨텍스트도 죽었을텐데..?
질문이 복잡해서 지피티한테 먼저 물어봤다
1번은.. 정확하지 않은 내용같았다.
그런데 2번, 처음보는 개념인 OSIV가 등장했다!
구글에 같은 이미지가 많길래 주워왔다..
트랜잭션은 죽더라도, 영속성 컨텍스트의 라이프사이클은 Request에 맞춰주는 기능이라고 한다.
스프링에서는 기본적으로 활성화 되어있다.
단, 트랜잭션은 Service 계층부터 살아있으니 컨트롤러에서 영속성 객체의 값을 변경하더라도 flush하지 않는다.
단점으로는, 컨트롤러와 뷰에서도 DB와의 커넥션을 물고 있다는 점이다.
만약 컨트롤러에서 외부 API를 아주 열심히..정말..오래오래.. 호출하고 있다고 하자
이 때, DB와는 관계없는 일이지만 커넥션을 쭉 물고있다. 따라서 이용자가 많아지면 커넥션 풀 관리가 정말 힘들어진다.
따라서, OSIV의 개념을 알고 로직에 따라 적절히 설정해 사용하는게 중요하겠다.