<aside> ❗
Session
은 JPA에서 EntityManager
를 의미
하이버네이트에서는 Session
이라고 부름spring.jpa.open-in-view: true
기본값→ 스프링 부트 실행 시 WARN 로그를 남기는 이유가 있다.
WARN 37102 --- [ restartedMain] JpaBaseConfiguration$JpaWebConfiguration :
spring.jpa.open-in-view is enabled by default. Therefore,
database queries may be performed during view rendering.
Explicitly configure spring.jpa.open-in-view to disable this warning
JPA가 언제 DB 커넥션을 가져오고 언제 반환할까 ?? 영속성 컨텍스트와 데이터베이스 커넥션은 굉장히 밀접하게 연관됨 즉, 영속성 컨텍스트와 데이터베이스 커넥션과 1:1로 쓰면서 동작해야 함
기본적으로 데이터베이스 트랜잭션을 시작할 때
,
JPA의 영속성 컨텍스트가
데이터베이스 커넥션을 획득한다
.
언제 DB에 커넥션을 돌려주는가 ??
[Open Session In View - true]
트랜잭션이 끝나도 영속성 컨텍스트를 끝까지 살려둔다. → API의 경우, API가 유저한테 반환될 때까지 → API가 반환될 때까지 지연로딩을 수행할 수 있어야 하기 때문 → View인 경우 View가 렌더링되어 유저한테 응답할 때까지 즉, 더 이상 필요 없는 단계가 될 때까지 영속성 컨텍스트 유지
응답할 때, 데이터베이스 커넥션을 돌려주고 영속성 컨텍스트 제거
OSIV 전략은 트랜잭션 시작처럼 최초 데이터베이스 커넥션 시작 시점부터 API 응답이 끝날 때까지 영속성 컨텍스트와 데이터베이스 커넥션을 유지한다.
그래서 지금까지 View Template이나 API 컨트롤러에서 지연 로딩이 가능했던 것
**지연 로딩은 영속성 컨텍스트가 살아 있어야 가능
**하고,
**영속성 컨텍스트는 기본적으로 데이터베이스 컨넥션을 유지
**한다.
이것 자체가 큰 장점
[장점]
[단점]
너무 오랜 시간 동안 데이터베이스 커넥션 리소스를 사용
**하기 때문에실시간 트래픽이 중요한 애플리케이션에서는 커넥션이 부족할 수 있다.
이것은 장애로 이어진다.spring.jpa.open-in-view: false
OSIV 종료
OSIV를 끄면 **트랜잭션을 종료할 때, 영속성 컨텍스트를 닫고, 데이터베이스 커넥션도 반환
**한다.
즉, 리소스를 낭비하지 않는다.
데이터베이스 커넥션을 트랜잭션을 짧은 기간 동안 유지
OSIV를 끄면 모든 지연로딩을 트랜잭션 안에서 처리해야 한다.
따라서 지금까지 작성한 많은 지연 로딩 코드를 트랜잭션 안으로 넣어야 한다는 단점이 있다.
view-template에서 지연로딩이 동작하지 않는다.
결론적으로 트랜잭션이 끝나기 전에 지연 로딩을 강제로 호출해 두어야 한다.
트랜잭션이 종료되기 전에 처리하거나 Fetch 조인을 사용하여 해결 </aside>
<aside> ❗
변환 로직 자체를 쿼리용 서비스에 작성
@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class OrderQueryService {
private final OrderService orderService;
public List<OrderDto> orderV2() {
List<Order> orders = orderRepository.findAllByString(new OrderSearch());
List<OrderDto> collect = orders.stream().map(o -> new OrderDto(o)).collect(toList());
return collect;
}
}
@GetMapping("/api/v2/orders")
public List<OrderDto> orderV2() {
return orderQueryService.orderV2();
}
실무에서 OSIV를 끈 상태로 복잡성을 관리하는 좋은 방법이 있다.
바로 Command와 Query를 분리하는 것이다.
보통 비즈니스 로직은 특정 엔티티 몇 개를 등록하거나 수정하는 것이므로 성능이 크게 문제되지 않는다.
**보통 성능 이슈는 조회에서 발생
**한다.
복잡한 화면을 출력하기 위한 쿼리는 화면에 맞추어 성능을 최적화 하는 것이 중요하다.
하지만 그 복잡성에 비해 핵심 비즈니스에 큰 영향을 주는 것은 아니다.
크고 복잡한 애플리케이션을 개발한다면, 이 둘의 관심사를 명확하게 분리하는 선택은
유지보수 관점에서 충분히 의미 있다.
→ 둘의 라이프싸이클이 다르므로 분리하지 않으면 유지보수성이 떨어짐
→ 뷰 로직이 자주 변경되는 반면, 핵심 비즈니스 로직은 거의 변경되지 않음
→ 둘의 라이프싸이클이 많이 다름
OrderService
보통 서비스 계층에서 트랜잭션을 유지한다. 두 서비스 모두 트랜잭션을 유지하면서 지연 로딩을 사용할 수 있다.
[참고]
[기타]
컨트롤러 → 도메인 서비스 → 애플리케이션 서비스 → 리포지토리
</aside>