• 티스토리 홈
starryeye
  • 프로필사진
    starryeye
    • 분류 전체보기 (189)
      • C++ (17)
      • Java (24)
      • OOP (5)
      • Spring Reactive Stack (12)
        • Reactive Streams (3)
        • Netty (4)
        • Reactor (1)
        • Webflux (3)
        • DB, Cache 연동 (1)
      • Spring (90)
        • Core (17)
        • MVC (33)
        • Client (2)
        • Security (4)
        • DB, Cache 연동 (33)
      • DataBase (12)
        • RDBMS (2)
        • NoSQL (10)
      • Message Broker (6)
      • Web (4)
      • Network (4)
      • 대규모 시스템 설계 (15)
  • 방문자 수
    • 전체:
    • 오늘:
    • 어제:
  • 최근 댓글
      등록된 댓글이 없습니다.
    • 최근 공지
        등록된 공지가 없습니다.
      # Home
      # 공지사항
      #
      # 태그
      # 검색결과
      # 방명록
      • Spring 과 JPA
        2024년 02월 14일
        • starryeye
        • 작성자
        • 2024.02.14.:24
        반응형

         

        J2EE 컨테이너 환경의 대표격인 Spring 에서

        JPA 를 사용할 경우 알아야할 중요한 개념을 나열해보겠다.

         

         

        순수하게 J2SE 환경에서 JPA 를 사용하면 개발자가 직접 EntityManager 를 생성해야하며,

        Transaction 도 관리해야한다.

         

        J2EE 환경에서 JPA 를 사용하면 트랜잭션 범위의 영속성 컨텍스트 전략이 기본으로 채택된다.

         

        Spring 에서 트랜잭션 범위와 영속성 컨텍스트 생존 범위가 동일한 전략을 따르면, 트랜잭션 AOP 를 활용한다.

         

         

        트랜잭션 범위와 영속성 컨텍스트 생존 범위가 동일한 전략

        해당 전략에서는 트랜잭션을 시작할 때, entityManager 를 생성하고

        트랜잭션이 종료 될 때, entityManager 도 닫힌다.

         

        트랜잭션이 같으면 동일한 EntityManager 를 사용하며, 동일한 영속성 컨텍스트를 사용하게 된다.

        트랜잭션이 다르면 다른 EntityManager 를 사용하며, 다른 영속성 컨텍스트를 사용하게 된다.

         

        트랜잭션 범위의 영속성 컨텍스트 전략을 사용하면,

        트랜잭션 범위에서 벗어난 계층(presentation layer 등) 에서의 엔티티는 준영속 상태이다.

         

        엔티티가 준영속 상태라면,

        변경 감지와 지연로딩이 동작하지 않는다.

        트랜잭션을 벗어난 범위 이므로..

        변경 감지의 기능이 동작하지 않는다라는 점은 문제가 되지 않고..

        지연로딩이 동작하지 않는다는 점은 문제가 될 수 있다.

         

        트랜잭션 범위를 벗어나서 지연로딩을 사용할 수 없는 문제는 2 가지 방법으로 해결가능하다.

        1. 트랜잭션 범위에서 미리 로딩 해놓기

        2. OSIV

         

         

        트랜잭션 범위에서 미리 로딩

        트랜잭션 범위에서 미리 로딩 해놓기의 방법은 총 3 가지가 존재한다.

        1. 글로벌 페치 전략을 Eager 로..

        -> 글로벌 페치 전략을 Eager 로 하면, 사용하지 않는 엔티티를 항상 로딩하여 성능상 문제가 될 수 있다.

        -> N+1 문제가 발생

        페치 조인을 사용하지 않은 JPQL 로 조회시, 즉시 로딩 전략에 의해 연관된 엔티티에 대한 추가적인 쿼리가 실행된다.

        (글로벌 페치 전략 보다 우선으로 동작하는 것이 JPQL 이다.)

         

        2. 페치 조인

        -> 연관된 엔티티까지 함께 조회 하므로 N+1 문제도 발생하지 않는다.

        연관된 엔티티를 함께 조회 하였으므로 글로벌 페치 전략이 무의미하다.

        그러나, 화면 별로 필요한 데이터에 따라 페치 조인을 무분별하게 사용하는 것은

        repository layer 가 presentation layer 을 논리적으로 의존하는 것일 수 있으니 검토가 필요하다.

         

        3. 강제 초기화

        트랜잭션 범위에서 미리 로딩을 위해 트랜잭션 범위를 벗어나기 직전에

        강제 초기화를 한다. (서비스 계층에서 하는게 마음에 안들면 Facade 계층을 만들어야할 수 도 있다.)

         

         

        OSIV (open session in view)

        OSIV 는 Hibernate 에서 사용하는 용어이며,

        JPA 공식 용어는 OEIV(open entitymanager in view) 이나 OSIV 로 관례상 불림

         

        OSIV 는 영속성 컨텍스트를 뷰까지 열어두는 기능이다.

        영속성 컨텍스트가 뷰까지 살아 있으면 엔티티도 영속 상태로 유지 되므로

        뷰에서도 지연 로딩을 사용할 수 있는 것이다.

         

        OSIV 의 구현 방식은 2 가지가 존재한다.

        1. 요청 당 트랜잭션의 OSIV

        2. 비즈니스 계층 트랜잭션의 OSIV

         

        하나 씩 알아보겠다.

         

        1. 요청 당 트랜잭션, OSIV

        요청 당 트랜잭션에서는 Client 의 요청이 들어오자마자 트랜잭션을 시작하고

        요청이 끝날 때 트랜잭션을 종료하는 것이다.

        이 방식도 트랜잭션 범위와 영속성 컨텍스트의 범위가 동일한 전략을 따른다.

         

        Spring 에서는 필터나 인터셉터에서 트랜잭션을 시작하고 종료하는 방식이다.

        영속성 컨텍스트 범위도 대폭 증가하여 필터, 인터셉터에서 시작 종료 되며

        presentation layer 에서도 영속성 컨텍스트가 살아 있는 것이다.

        -> 따라서, presentation layer 에서 지연 로딩이 가능하지만

        필터나 인터셉터에서 트랜잭션이 종료되어 presentation layer 에서 변경한 엔티티가

        변경 감지에 포함된다.

         

        2. 비즈니스 계층 트랜잭션, OSIV (트랜잭션 범위와 영속성 컨텍스트 생존 범위가 다른 전략)

        해당 방법은 Spring 이 제공하는 방법이며,

        비즈니스 계층에서만 트랜잭션을 사용하는 OSIV 이다. (@Transactional 범위)

        -> 트랜잭션 범위와 영속성 컨텍스트 범위가 다르다.

         

        동작 순서를 알아보자

        1. Client 요청이 들어오면 Servlet Filter 나 Spring Interceptor 에서

        영속성 컨텍스트를 생성한다. (트랜잭션 시작은 하지 않음)

         

        2. Service layer 에서 @Transactional 로 트랜잭션을 시작할 때

        미리 생성해둔 영속성 컨텍스트를 이용하여 트랜잭션 시작

         

        3. Service layer 가 끝나면 트랜잭션을 커밋 하고 영속성 컨텍스트를 flush 한다.

        (트랜잭션 종료, 영속성 컨텍스트는 유지)

         

        4. Controller layer (View 포함) 에서도 영속성 컨텍스트가 유지 되므로

        조회된 엔티티는 영속 상태이다. (지연 로딩 가능)

         

        5. Servlet Filter 나 Spring Interceptor 에서 영속성 컨텍스트를 종료한다.

        (트랜잭션 커밋은 아니므로 flush 를 호출 하지는 않는다.)

         

         

        참고. 트랜잭션 커밋과 영속성 컨텍스트

        트랜잭션 커밋 == 영속성 컨텍스트 Flush + 실제 commit

        영속성 컨텍스트 Flush == 변경 감지 + 쓰기 지연 SQL flush

         

         

        참고. 영속성 컨텍스트와 엔티티 조회/수정

        영속성 컨텍스트는 트랜잭션 범위 안에서 엔티티를 조회하고 수정할 수 있다.

        영속성 컨텍스트는 트랜잭션 범위 밖에서 엔티티를 조회만 할 수 있다.

        (직접 flush 호출하여 수정 시, TransactionRequiredException 발생)

         

        따라서, 스프링이 제공하는 OSIV 를 사용하면, presentation layer 에서는

        트랜잭션 범위 밖이므로 조회만 가능하다.

        영속상태의 엔티티 이지만, 수정하여도 filter, interceptor 에서 flush 하지 않고 close 이므로

        변경감지가 동작하지는 않는다.

         

        참고.

        controller 에서 service 를 호출하여 영속상태의 엔티티를 얻고

        엔티티를 수정한 상태에서 또 다른 service 를 호출하고 트랜잭션 커밋을 하면..

        controller 에서 수정한 엔티티가 변경감지로 반영 되어버린다...

        -> 서로 다른 트랜잭션이지만.. filter, interceptor 에서 생성한 동일한 영속성 컨텍스트를 공유하여

        사용하기 때문이다.

         

        참고.

        스프링 OSIV 에서 트랜잭션이 commit 되어도 DB connection 은 반환 되지 않는다.

        반환 되지 않았기 때문에 지연 로딩도 가능한 것..

        반응형

        'Spring > DB, Cache 연동' 카테고리의 다른 글

        DBCP (HikariCP)  (0) 2024.04.22
        Spring Data JPA (Hibernate), N + 1 Query Problem  (0) 2024.02.20
        JPA 등록, 기본 키 생성 전략  (0) 2023.06.19
        JPA 변경 감지와 플러시  (0) 2023.06.15
        JPA Entity Default Constructor  (1) 2023.06.07
        다음글
        다음 글이 없습니다.
        이전글
        이전 글이 없습니다.
        댓글
      조회된 결과가 없습니다.
      스킨 업데이트 안내
      현재 이용하고 계신 스킨의 버전보다 더 높은 최신 버전이 감지 되었습니다. 최신버전 스킨 파일을 다운로드 받을 수 있는 페이지로 이동하시겠습니까?
      ("아니오" 를 선택할 시 30일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)
      목차
      표시할 목차가 없습니다.
        • 안녕하세요
        • 감사해요
        • 잘있어요

        티스토리툴바