Spring

스프링 JPA 환경 변수 중 몰랐던 것들

미스터머글 2022. 11. 1. 15:22
728x90
반응형

⚠️ 경고 ⚠️

본 카테고리, Dev Memo는 필자가 깊게 다루기는 귀찮지만 궁금한 것들을 체험해보고 간단하게 기록을 남기는 공간입니다. 디버깅 노트, 써드파티 라이브러리 사용기, 버전 업데이트, 어이없는 실수, 오탈자 발견 등. 각종 시덥지 않은 내용이 들어 갈 수 있다는 점 참고바랍니다. (우헤헿)

 

 

open-in-view (Open-Session-In-View)

// application.yml
spring:
  jpa:
    open-in-view: false

(출처 : 공부기록) 관례상 OSIV 라고 한다. true일 경우 영속성 컨텍스트가 트랜잭션 범위를 넘어선 레이어까지 살아있다. Api라면 클라이언트에게 응답될 때까지, View라면 View가 렌더링될 때까지 영속성컨텍스트가 살아있다. false일 경우 트랜잭션을 종료할 때 영속성 컨텍스트 또한 닫힌다. 

영속성 컨텍스트를 유지한다는 건, DB Connection 또한 계속 가지고 있다는 뜻이다. 실시간 트래픽이 중요한 어플리케이션에서는 DB Connection이 모자를 수 있다. 성능이 중요하다면 OSIV는 false로 설정하자.

 

(출처: 경호의 공부방) OSIV(Open Session In View)는 영속성 컨텍스트를 뷰까지 열어두는 기능이다. 영속성 컨텍스트가 유지되면 엔티티도 영속 상태로 유지된다. 뷰까지 영속성 컨텍스트가 살아있다면 뷰에서도 지연 로딩을 사용할 수가 있다.
이 전략은 너무 오랜시간동안 데이터베이스 커넥션 리소스를 사용하기 때문에, 실시간 트래픽이 중요한 애플리케이션에서는 커넥션이 모자랄 수 있다. 이것은 결국 장애로 이어진다. 예를 들어서 컨트롤러에서 외부 API를 호출하면 외부 API 대기 시간 만큼 커넥션 리소스를 반환하지 못하고, 유지해야 한다. → OISV의 치명적인 단점, 커넥션을 영속성 컨텍스트가 종료될 때까지 1:1로 계속 물고 있음
실무에서 OSIV를 끈 상태로 복잡성을 관리하는 좋은 방법이 있다. 바로 Command와 Query를 분리하는것이다.  복잡한 화면을 출력하기 위한 쿼리는 화면에 맞추어 성능을 최적화 하는 것이 중요하다. 하지만 그 복잡성에 비해 핵심 비즈니스에 큰 영향을 주는 것은 아니다. 그래서 크고 복잡한 애플리케이션을 개발한다면, 이 둘의 관심사를 명확하게 분리하는 선택은 유지보수 관점에서 충분히 의미 있다. 단순하게 설명해서 다음처럼 분리하는 것이다.

 

예시 : OrderService
- OrderService: 핵심 비즈니스 로직
- OrderQueryService: 화면이나 API에 맞춘 서비스 (주로 읽기 전용 트랜잭션 사용)

 

 

 

enable_lazy_load_no_trans

// application.yml
spring:
  jpa:
    properties:
      hibernate:
        enable_lazy_load_no_trans: true // 비추천!!

(출처 : 실전! 스프링 부트와 JPA 활용) OSIV를 사용하면 하나의 데이터베이스 커넥션을 이미 획득한 상태로 지연로딩을 처리하기 때문에 여러번 지연로딩을 해도 하나의 데이터베이스 커넥션을 계속 이어서 사용합니다.
enable_lazy_load_no_trans 옵션은 OSIV와 비슷하기는 한데, 영속성 컨텍스트가 종료되어도, 새로운 데이터베이스 커넥션을 획득해서 지연로딩을 가능하게 해줍니다. 이 방법은 여러번 지연로딩이 있으면 그때마다 각각 새로운 데이터베이스 커넥션을 획득합니다. 따라서 성능상 매우 좋지 않습니다.
OSIV는 장단점을 잘 이해하고 매우 신중하게 사용해야 하는데, enable_lazy_load_no_trans 옵션은 성능까지 좋지 않아서, 더 권장하지 않습니다. (공식 메뉴얼에서도 권장하지 않습니다.)

 

(출처 : iamcoder.log) 해당 옵션은 말 그대로 lazy 로딩 시 LazyInitializationException 발생 할 것 같은 경우에 임시로 db에 연결해 데이터를 가져오도록 하는 옵션이다. Lazy 로드 대상이 늘어 날수록 서버의 db 커넥션 풀은 빈곤해지고 역시 성능 감소로 이어질 수 있다.

 

(출처 : https://suhwan.dev/2019/10/27/hibernate-detached-entity-proxy-initialization/) enable_lazy_load_no_trans 설정은 안티 패턴이다. ... N+1 문제를 방지할 수 없는 것은 물론이고, 프록시를 초기화할 때마다 새로운 EntityManager와 트랜잭션을 열고 닫고를 반복해야 하고, 이에 따라 JDBC 커넥션도 점유했다 반납했다를 반복하게 된다. 이는 리소스 낭비다. 이런 옵션이 필요한 상황이 있다면 트랜잭션과 EntityManager가 닫히기 전에 원하는 엔티티를 미리 초기화해놓는 방식으로 해결해야 할 것이다.

 

 

 

 

provider_disables_autocommit

// application.yml
spring:
  jpa:
    properties:
      hibernate:
        connection:
          provider_disables_autocommit: true

(출처 : 기록은 기억을 지배한다) provider_disables_autocommit 설정은 DBCP(커넥션 풀) 설정의 autoCommit을 믿고 사용하는 설정이다. 즉, DBCP의 autoCommit 설정이 매우 중요하다.
만약 provider_disables_autocommit=true로 놓고 DBCP의 autoCommit을 true로 놓게되면? DBCP가 커넥션을 생성하여 가지고 있으므로, 생성 시점부터 항상 autoCommit=true라 트랜잭션 안에 메소드가 수행하다 실패해도 롤백이 안된다. 따라서 provider_disables_autocommit=true를 사용할거면 DBCP의 autoCommit을 false로 놓아서 트랜잭션 단위로 동작할 수 있도록 해야한다. (AutoCommit에 대한 이해가 필요하면 위 출처에서 해당 내용을 참고할 것)

 

 

 

.

728x90
반응형