제육's 휘발성 코딩
article thumbnail
반응형

OSIV 전략

OSIV 란 Open Session In View 라는 하이버네이트 전략이며, JPA에선 Session 대신 EntityManager 지만 관례상 통합해서 OSIV라고 부른다.

OSIV ON

image

  • 스프링 부트를 시작 시점에 다음과 같은 warn 로그로 남는다. 그 이유는 spring.jpa.open-in-view가 기본 값이 true로 설정되어 있기 때문이다.

image

  • OSIV 전략은 트랜잭션 시작처럼 최초 데이터베이스 커넥션 시작 시점부터 API 응답이 끝날 때 까지 영속성 컨텍스트와 데이터베이스 커넥션을 유지한다. 그래서 지금까지 View Template이나 API 컨트롤러에서 지연 로딩이 가능한 것이다.
  • 지연로딩은 영속성 컨텍스트가 살아있어야 가능하고, 영속성 컨텍스트는 데이터베이스 커넥션을 유지한다.

여기서 발생할 수 있는 문제점은 오랜 시간동안 데이터베이스 커넥션 리소스를 사용하기 때문에, 실시간 트래픽이 중요한 애플리케이션에는 커넥션이 모자랄 수 있고, 이는 곧 장애로 이어진다.

예를 들어 외부 API를 호출하는 경우 대기 시간만큼 커넥션 리소스를 반환하지 못하고, 유지해야한다.

 

OSIV OFF

image

  • spring.jpa.open-in-view : false 의 경우 다음 그림과 같이 트랜잭션을 종료할 때 영속성 컨텍스트를 닫고, 데이터베이스 커넥션도 반환한다. 따라서 커넥션 리소스를 낭비하지 않는다.
  • OSIV를 끄면 모든 지연로딩을 트랜잭션 안에서 처리해야 한다. 또한 view template에서 지연로딩이 동작하지 않는다. 결론적으로 트랜잭션이 끝나기 전에 지연 로딩을 강제로 호출해두어야한다.

image

  • OSIV를 OFF 설정 (application.yml)한 후에 기존의 API를 실행해보면 다음과 같이 지연 로딩 예외가 발생하는 것을 볼 수 있다.
@GetMapping("/api/v1/orders")
public List<Order> ordersV1() {
  List<Order> all = orderRepository.findAllByString(new OrderSearch());
  for (Order order : all) {
    order.getMember().getName(); // Lazy 강제 초기화
    order.getDelivery().getAddress(); // Lazy 강제 초기화
    List<OrderItem> orderItems = order.getOrderItems();
    orderItems.stream().forEach(o -> o.getItem().getName()); // Lazy 강제 초기화
  }
  return all;
}
  • 다음 코드를 살펴보자. 지연 로딩을 사용했기 때문에 그래프 탐색 시 Lazy가 강제 초기화되는 코드이다. findAllByString의 메서드가 끝난 순간 트랜잭션이 종료되고 영속성 컨텍스트가 죽어있기 때문이다.
  • 해결 방법은 for문 아래의 코드를 비즈니스 로직에서 처리하거나, 페치 조인을 사용해야 한다.
@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class OrderQueryService {
  // ...
}
  • 다음과 같이 트랜잭션안에서 필요한 비즈니스 로직들을 실행시키도록 설정하여 해결할 수 있다.

 

커멘드와 쿼리 분리

실무에서 OSIV를 끈 상태에서 복잡성을 관리하는 방법은 커맨드와 쿼리를 분리하는 것이다. 크고 복잡한 애플리케이션을 개발한다면, 이 둘의 관심사를 명확하게 분리하는 선택이 유지보수 관점에서 좋다.

관련 문서 : https://en.wikipedia.org/wiki/Command%E2%80%93query_separation

커넥션을 많이 사용하는 API의 경우 OSIV를 끄고, 아닌 경우 OSIV를 키자.

 


본 포스팅은 인프런 김영한님 강의(실전! 스프링 부트와 JPA 활용2)를 토대로 정리한 내용입니다.

반응형
profile

제육's 휘발성 코딩

@sasca37

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요! 맞구독은 언제나 환영입니다^^