[영상후기] OSIV - 이건우 | 백엔드 데브코스 3기 | 20230203

박철현·2024년 10월 24일
0

영상후기

목록 보기
155/160

movie

SpringBoot Application 실행하며 발생하는 Warn log

2024-10-24T21:32:47.997+09:00 WARN 5128 ---
[ main] 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
  • spring.jpa.open-in-view is enabled by default.
    • OSIV 기능이 default로 켜져있습니다.
  • Therefore, database queries may be performed during view rendering.
    • 뷰를 렌더링 하면서 쿼리가 나갈 수 있어요
  • Explicitly configure spring.jpa.open-in-view to disable this warning
    • 명시적으로 OSIV 기능을 설정하여 WARNING을 없애세요

OSIV 기능 꺼보기

영속성 컨텍스트는 언제 만들어지고 없어질까요?

  • 트랜잭션이 시작될 때 만들어져 트랜잭션이 커밋된 후 없어진다.

머쓱이의 문제

  • 머쓱이는 게시글 단건 조회 api를 만들었다.
  • 단건 조회는 PK로 Repository를 조회하는 간단한 api이다.
  • 머쓱이는 Controller까지 Post(게시글) entity를 가져와 PostDto로 변환하였다.
  • Post는 User와 다대일 연관관계 매핑이 되어있다.
  • PostDto는 Post 정보와 User 정보를 가지고 있다.

Error 발생!

트랜잭션이 종료 되었는데, Lazy Loading인 객체를 참조하려 해서 Error 발생

  • Service에서 트랜잭션 종료 되어 영속성 컨텍스트 사라짐
  • Controller 단에서 프록시 객체인 user를 초기화하고 해당 user 객체의 속성을 가져오려 했지만 준영속 상태이기 때문에 예외 발생

  • 출처 : 뤼튼

에러 메세지

could not initialize proxy ~~

  • 프록시를 초기화 할 수 없습니다.
    no Session
  • 영속성 컨텍스트가 없어요!

문제

필요성

  • Transaction 밖에서도 영속성 컨텍스트가 계속 존재하여 데이터베이스 커넥션을 유지하고 영속성 컨텍스트를 사용할 수 있는 기능이 필요하다!

OSIV(Open Session In View)

  • 영속성 컨텍스트를 요청이 들어올 때 미리 만들고 응답을 할 때까지 영속성 컨텍스트를 유지시켜주는 기능

Spring 제공 OSIV

  • 하이버네이트에서는 OSIV란 용어를 사용하고 JPA에서는 OEIV라 하지만 관례상 OSIV라 부른다.
    • 하이버네이트 OSIV 서블릿 필터
    • 하이버네이트 OSIV 스프링 인터셉터
    • JPA OEIV 서블릿 필터
    • JPA OEIV 스프링 인터셉터
  • 필터나 인터셉터에서 미리 영속성 컨텍스트를 만들어서 사용

application.yml에서의 OSIV 설정

JPA에서 제공해주는 Interceptor 사용

spring
  jpa:
    open-in-view : true
  • 인터셉터에서 영속성 컨텍스트 생성 확인

OSIV 기능을 키고 다시 실행

  • 트랜잭션이 끝나도 영속성 컨텍스트를 종료하지 않는다.
  • 인터셉터에서 영속성 컨텍스트를 종료한다.

머쓱이 문제 해결!

  • Transaction 밖에서도 영속성 컨텍스트를 사용하여 id와 name을 LazyLoading 했다.
{
  "postId" : 1,
  "title" : "spring",
  "content" : "osiv",
  "userId" : 1,
  "userName" : "이건우",
  "createdAt" : "2023-01-24 05-21-18"
}

DB 커넥션 유지하고 영속성 컨텍스트를 사용할 수 있으니 무조건 사용해야 하는 것 아냐?!

주의사항

  • Transaction 밖에서도 조회를 위한 쿼리가 나가게 되어 성능을 따질 때 확인해야 할 부분이 넓어진다.
  • DB 커넥션 시작 시점부터 응답이 나갈 때까지 데이터베이스 커넥션을 유지하여 커넥션이 부족할 수 있다.

OSIV의 대안

  • Transaction 밖에서 조회를 하지 않기 위해 어떻게 해야 할까?
    • Transaction 안에서 미리 조회 해야한다.

강제 초기화

  • 머쓱이가 Entity -> Dto 변환을 트랜잭션 안에서 처리하였다면 에러가 나지 않았을 것이다.
    • 혹은 fetchJoin 같은거로 해서 LazyLoading 없이도 가능
  • Lazy Loading을 트랜잭션 안에서 하여 초기화 작업을 트랜잭션 안에서 끝낸다.

OSIV 장점

  • 지연 로딩을 적극적으로 활용할 수 있다.
  • 지연 로딩을 사용할 수 있어 Service에 초기화를 위한 코드를 작성하지 않아도 된다.

OSIV의 단점

  • 응답이 나갈 때까지 데이터베이스 커넥션을 유지하여 커넥션이 부족할 수 있다.
  • Transaction 밖에서도 조회를 위한 쿼리가 나가게 되어 성능을 따질 때 확인해야 할 부분이 넓어진다.

OSIV를 사용하는 것이 좋을까?

  • 정답은 X, 유연히 판단하여 적용할 수 있는 개발자가 되자!

OSIV를 명시적으로 설정하여 WARN 로그를 없애자!


추가 내용

OSIV를 끄지 않으면 @Transaction을 구분 못한다

한 요청 내에서 여러 트랜잭션을 구분하기 어렵다

  • OSIV가 활성화되면, 요청의 생애주기 동안 영속성 컨텍스트가 유지되기 때문에 여러 트랜잭션을 명확하게 구분하기가 어렵습니다.

Interceptor에서 영속성 컨텍스트를 생성

  • 요청이 시작될 때 Interceptor에서 영속성 컨텍스트가 생성되고, 요청이 끝날 때 clear됩니다.
    • 이때 commit과 clear는 별개로 처리됩니다.
  • 트랜잭션이 커밋된 후에도 영속성 컨텍스트는 유지되며, 요청의 마지막 단계인 View를 반환할 때까지 활성화됩니다.

@Transactional(readOnly = true)

  • 더티 체킹을 위한 스냅샷을 저장하지 않으므로 성능이 향상될 수 있습니다. 이는 OSIV와 관계없이 적용됩니다.

OSIV를 끄면 Transaction 사용 시 주의해야 한다

트랜잭션 범위를 벗어나면 해당 Entity는 준영속 상태가 되어 영속성 컨텍스트에서 관리하지 않는다.

  • 트랜잭션이 종료되면 해당 엔티티는 영속성 컨텍스트에서 관리되지 않게 됩니다.

Lazy Loading 사용 시 Exception 발생

  • 해당 엔티티의 속성으로 가진 참조 변수에 저장된 Proxy 객체를 통해 Lazy Loading을 시도할 경우, 영속성 컨텍스트가 닫혀 있으므로 LazyInitializationException이 발생합니다.

무분별하게 @Transactional을 사용

  • 트랜잭션이 길어지면 DB 커넥션이 오랫동안 유지되므로, 커넥션 풀이 소진될 수 있습니다.
  • 특히 실시간 서비스에서는 이로 인해 성능 저하가 발생할 수 있습니다.
  • 따라서 필요한 범위 내에서만 트랜잭션을 유지해야 합니다.

@Transactional(readOnly = true) 옵션

  • OSIV를 끄더라도 @Transactional(readOnly = true) 옵션은 여전히 더티 체킹을 위한 스냅샷을 저장하지 않는 특성이 적용됩니다.
  • 데이터베이스에 대한 읽기 전용 작업에 최적화된 설정이기 때문에, 성능 향상에 기여할 수 있습니다.

장점

Data 일관성 보장 가능

  • 트랜잭션 사용의 목적은 DB의 데이터의 일관성과 무결성을 보장하기 위해 사용하는데 목적
  • 읽기 전용으로 설정하면 실수로 데이터를 수정해서 일관성을 위반할 가능성이 낮아진다.
  • 조회 메서드에서도 일관성을 위반할 우려가 있어 항상 주의를 해야한다.

가독성 향상

  • @Transactional(readOnly=true) 설정된 메서드가 DB에서 데이터를 읽기만 한다는 것을 명확하게 확인할 수 있어 가독성이 향상된다.

성능 최적화

  • 해당 메서드가 읽기만 한다는 것을 DB에 알려줌으로써 쿼리 및 캐싱을 최적화 가능
  • JPA의 변경감지(Dirty Checking)를 위한 스냅샷을 저장 하지 않아 성능 향상 기대
    • 영속성 컨텍스트는 Entity 조회 시 초기 상태에 대한 snapshot 저장
    • 트랜잭션 Commit 될 때, 초기 상태의 정보를 가지는 snapshot과 Entity의 상태를 비교하여 변경된 내용에 대해 update query 생성해 쓰기 지연 저장소에 저장
    • flush 후 Commit 함으로써 update 메서드를 명시적으로 사용하지 않아도 Entity 수정됨
  • readOnly = true를 설정하게 되면 JPA의 세션 플러시 모드를 MANUAL로 설정
    • 트랜잭션 내에서 사용자가 수동으로 flush를 호출하지 않으면 flush가 자동으로 수행 안됨

Replication 시 readOnly = true 설정 -> Slave DB에서 데이터 가져오도록 동작

  • Replication 목적에 맞게 트래픽 분산을 온전히 적용할 수 있는 추가적 이점 존재
profile
비슷한 어려움을 겪는 누군가에게 도움이 되길

0개의 댓글

관련 채용 정보