API 개발 고급(실무 필수 최적화)
OSIV와 성능최적화
- Open Session In View: hibernate
- Open EntityManager In View: JPA
OSIV :ON
- spring.jpa.open-in-view: true 기본값
- OSIV 전략: 최초 데이터베이스 커넥션 시작(트랜잭션 시작)부터 트랜잭션이 끝나도 영속성 컨텍스트와 데이터베이스 커넥션을 유지
- API 경우: API 응답이 반환될 때까지 DB커넥션 유지
- View Template 경우: view template이 랜더링 완성되고 response 나갈때까지
장점
- lazy로딩은 영속성 컨텍스트가 살아있어야 가능
- 영속성 컨텍스트는 db커넥션 유지 -> 영속성 컨텍스트의 생존범위가 확장(controller나 view에서도 사용가능)
단점
- 너무 오랫동안 db 커넥션을 유지하기 때문에 실시간 트래픽이 중요한 application에서는 db 커넥션이 모자랄 수 있음 -> 장애 유발
OSIV :OFF
- spring.jpa.open-in-view: false
- 트랙잭션이 끝나면 영속성 컨테스트도 닫고 db커넥션도 반환
장점
- db커넥션을 짧게 유지 -> 커넥션 리소스 낭비 하지않음, 커넥션 유연하게 사용가능
단점
- 모든 lazy 로딩 코드를 트랜잭션 안에 넣어야함
- view template에서 지연로딩이 동작하지 않음
- 트랜잭션이 끝나기 전에 지연 로딩을 강제로 호출해야함
커멘드와 쿼리 분리
- OSIV를 끈 상태로 복잡성 관리 방법 -> Command와 Query를 분리
- Controller에서 지연로딩을 써야할 때, Query용 Service를 따로 생성
API
@GetMappint("/api/v3/orders")
public List<OrderDto> ordersV3(){
return orderQueryService.ordersV3();
OrderQueryService
@Transactional(readOnly = true)
public class OrderQueryService{
public List<OrderDto> ordersV3(){
List<OrderDto> orders = orderRepository.findAllWithItem();
List<OrderApiController.OrderDto> result = orders.strea().
.map(o -> new OrderApiController.OrderDto(o))
.collect(toList());
return result;
- OrderService
- OrderService: 핵심 비즈니스 로직
- OrderQueryService: 화면이나 API에 맞춘 서비스 (주로 읽기 전용 트랜잭션 사용)
- 두 서비스 모두 트랜잭션을 유지하면서 지연 로딩을 사용 가능
고객 서비스의 실시간 API는 OSIV를 끄고, ADMIN 처럼 커넥션을 많이 사용하지 않는
곳에서는 OSIV를 켜는 걸 추천! (한 프로젝트라도 배포를 다르게 한다면)