커넥션이 오래 물리는 걸 줄이려고 spring.jpa.open-in-view를 false로 껐다. 이론은 알고 있었다. OSIV가 켜져 있으면 뷰를 렌더링할 때까지 영속성 컨텍스트와 커넥션이 살아 있으니, 트래픽이 몰릴 때 커넥션 점유가 길어진다. 그래서 껐는데, 끄자마자 여기저기서 예외가 터졌다.
org.hibernate.LazyInitializationException:
could not initialize proxy - no Session
지연 로딩할 세션이 이미 닫혔다
OSIV를 끄면 트랜잭션이 끝나는 순간 영속성 컨텍스트도 닫힌다. 그런데 컨트롤러나 뷰에서 그제야 연관 엔티티를 지연 로딩하려고 하면, 붙잡을 세션이 없어서 위 예외가 난다. 그동안은 OSIV가 세션을 뷰까지 열어 둔 덕에 문제가 안 보였을 뿐, 사실은 트랜잭션 밖에서 쿼리가 나가고 있었던 거다.
필요한 데이터는 트랜잭션 안에서 끝내기
해법은 서비스 계층, 즉 트랜잭션 경계 안에서 필요한 연관 데이터를 미리 가져와 DTO로 변환해서 내보내는 것이었다. 화면에 뭐가 필요한지를 서비스가 알고 있게 하고, 컨트롤러는 이미 완성된 DTO만 받게 했다. fetch join이나 DTO 프로젝션으로 필요한 걸 트랜잭션 안에서 확정하고 나니, 뷰에서 엔티티를 건드릴 일이 없어졌다. OSIV를 끈 김에 계층 간 책임도 더 또렷해졌다. 커넥션 점유 시간은 덤으로 짧아졌다.