JPA/JPA 활용과 주의사항들

OSIV - DB Transaction의 지속 범위

Recfli 2024. 2. 19. 21:12

[ OSIV 개념 익히기 ]

 OSIV는 open-session-in-view의 줄인 말으로 OSIV 옵션이 켜져있으면 트랜잭션이 애플리케이션 어디서든 유지되게 해준다. 반대로 OSIV 옵션이 꺼져있으면 트랜잭션이 service와 repository 계층에서만 살아있다.

 

OSIV 생명 주기:

 

 OSIV 옵션은 자동적으로는 켜져있다. 일반적으로 Bean에 등록된 어디서든 Entity를 수정하면 영속성 컨텍스트가 관리하는 범위 내에 있기 때문에 지연로딩으로 값을 가져올 수 있다. 그렇기 때문에 웬만해서는 LazyInitializationException 에러가 나는 경우는 OSIV 옵션이 켜진 상태에서는 일어나지 않는다. 

 

 만약에 값을 끄고 싶다면 다음과 같이 application.yml이든 어딘가에 다음처럼 코드를 한 줄 추가해주면 된다.

 

application.yml

  jpa:
    hibernate:
      ddl-auto: create
    properties:
      hibernate:
#        show_sql: true
        format_sql: true
        # 한꺼번에 땡겨올 데이터 양 선정 N+1 문제 해결
        default_batch_fetch_size: 100
    # 영속성 컨텍스트가 커넥션을 어디까지 물고 있냐를 결정
    open-in-view: false

 

[  OSIV 옵션 - true ]

 OSIV 옵션이 true일 때에는 다양한 장점이 있다. 우선 따로 영속성 컨텍스트 범위와 관련없이 어디서든 @Transactional 범위 내에 있다면 자유롭게 Entity 수정, 조회를 할 수 있다. 그렇기 때문에 코드 작성하는데에 있어서 따로 쿼리와 커맨드를 엄밀하게 분리하지 않아도 된다. 또한 컨트롤러에서 간단하게 처리할 수 있는 부분이면 넣어서 가독성이나 응집성을 높일 수 있다.

 

 하지만 문제점이 있다. @Transactional을 무분별하게 사용했을 때와 동일한 이슈인데, @Transactional에서 DB에서 가져오기만 하는 로직이 아니라 다른 외부나 사용자의 응답을 받고 Timeout까지 대기해야 되는 상황이거나 복잡한 연산을 요구하는 로직이 함께 트랜잭션과 물고 돌아갈 때 문제가 발생한다. 그 시간 동안 다른 요청을 처리할 수 있는데, 시간 낭비를 하게 된다.

 

 그렇기 때문에 잠깐 간단한 프로젝트거나 정말 요청이 별로 들어오지 않는 서버에만 이 옵션을 true로 놓는 것을 권장한다.

[ OSIV 옵션 - false ]

 OSIV 옵션이 false일 때에는 쿼리와 커맨드를 분리하고 본인이 트랜잭션과 관련된 로직들을 모두 Service 혹은 Repository 계층으로 내려야 한다. 그리고 범위를 벗어난 걸 인지 못한 채로 코드를 작성하다보면 수 많은 LazyInitializationException을 맛볼 수 있다. 이 부분에 대한 해결방법은 다음 글을 참고 바란다. 하지만 장점은 위에서 말한 한 커넥션이 물고 안 놔줘서 말라버리는 현상을 방지할 수 있다. 이것만으로도 엄청 큰 장점이라고 한다.

 

[ 참고 자료 ]

실전! 스프링 부트와 JPA 활용2 - 김영한 강의