JPA에 대해 알아보자 : 13장 웹애플리케이션과 영속성 관리

ParkIsComing·2023년 9월 18일

Spring

목록 보기
14/21
post-thumbnail

책 [자바 ORM 표준 JPA 프로그래밍]을 참고하여 작성하였습니다.

1. 트랜잭션 범위의 영속성 컨텍스트

1) 스프링 컨테이너의 기본 전략

  • 스프링 컨테이너는 트랜잭션 범위의 영속성 컨테이너 전략을 기본으로 사용한다.
    (=트랜잭션 범위와 영속성 컨텍스트의 생존 범위가 같다)
  • 비즈니스 로직을 시작하는 서비스 계층에 @Transactional 애노테이션을 선언해서 트랜잭션을 시작
  • 이 애노테이션이 있으면 호출한 메소드를 실행하기 직전에 스프링의 트랜잭션 AOP가 먼저 동작
  • 트랜잭션 AOP는 대상 메서드 호출 전 트랜잭션 시작 & 대상 메서드 정상 종료시 트랜잭션 커밋
  • 트랜잭션을 커밋하면 JPA는 먼저 영속성 컨텍스트를 플러시해서 변경 내용을 DB에 반영 -> 그다음에 DB 트랜잭션 커밋
  • 예외가 발생하면 트랜잭션을 롤백(커밋x)하고 종료하는데 이때는 플러시 호출 x
  • 다양한 위치에서 엔티티 매니저를 주입 받아 사용해도 트랜잭션이 같으면 항상 같은 영속성 컨텍스트 사용
  • 트랜잭션이 다르면, 같은 엔티티 매니저를 사용해도 트랜잭션에 따라 접근하는 영속성 컨텍스트가 다르다.

2. 준영속 상태와 지연 로딩

준영속 상태와 변경 감지

  • 변경 감지 기능은 서비스 계층까지만 동작하고, 프리젠테이션 계층에서는 동작하지 않음
  • 비즈니스 로직은 서비스 계층에서 끝내고, 프리젠테이션 계층은 데이터를 보여주는 데 집중해야 한다. 따라서 이는 문제가 되지 않음

준영속 상태와 지연 로딩

  • 준영속 상태는 영속성 컨텍스트가 없으므로 지연로딩을 할 수 없다.

해결 방법 1: 뷰가 필요한 엔티티를 미리 로딩해두기

  • 방법1. 글로벌 페치 전략 수정
    • @ManyToOne(fetch = FetchType.EAGER)
  • 방법2. JPQL 페치 조인
    • JPQL: select o from Order o -> select o from Order o join fetch o.member로 변경
  • 방법3. 강제로 초기화
    • 영속성 컨텍스트가 살아있을 때 프리젠테이션 계층이 필요한 엔티티를 강제로 초기화해서 반환
    • 예시 : order.getMember().getName()
    • 비즈니스 로직을 담당하는 서비스 계층에서 이처럼 프리젠테이션 계층을 위한 일(프록시 초기화)까지는 하는 것은 좋지 않다.
    • 이때는 프리젠테이션 계층과 서비스 계층 사이에 FACADE 계층을 하나 더 두어 서비스 계층과 프리젠테이션 계층 사이에 논리적인 의존성을 분리할 수 있다. (이때는 FACADE 계층에서 트랜잭션을 시작한다.)

해결방법 2: OSIV를 사용해서 엔티티를 항상 영속 상태로 유지하기

  • OSIV = Open Session In View. 영속성 컨텍스트를 뷰까지 열어둔다는 것.
  • 그러면 뷰에서도 지연로딩이 가능함.

1) 요청 당 트랜잭션 방식의 OSIV

2) 스프링 OSIV : 비즈니스 계층 트랜잭션

  • OSIV를 사용하기는 하지는 트랜잭션은 비즈니스 계층에서만 사용한다.
  • 영속성 컨텍스트를 프리젠테이션 계층까지 유지한다.
  • 프리젠테이션 계층에는 트랜잭션이 없으므로 엔티티를 수정할 수 없다. (프리젠테이션 계층에서 수정해도 수정 내용을 db에 반영하지 않는다.)
  • 프리젠테이션 계층에는 트랜잭션이 없지만 트랜잭션 없이 읽기를 사용해서 지연로딩을 할 수 있다.
  • 종류
    • 하이버네이트 OSIV 서블릿 필터
    • 하이버네이트 OSIV 스프링 인터셉터
    • JPA OSIV 서블릿 필터
    • JPA OEIV 스프링 인터셉터
  • 동작 원리
    • 클라이언트 요청이 들어오면 서블릿 필터스프링 인터셉터에서 영속성 컨텍스트 생성 (아직 트랜잭션 시작x)
    • 서비스 계층에서 트랜잭션을 시작하면(@Transactional) 앞에서 생성해둔 영속성 컨텍스트에 트랜잭션 시작
    • 비즈니스 로직을 실행하고 서비스 계층이 끝나면 트랜잭션을 커밋하면서 영속성 컨텍스트를 플러시(트랜잭션만 종료하고 영속성 컨텍스트는 살려둠)
    • 서블릿 필터스프링 인터셉터로 요청이 들어오면(클라이언트 요청이 끝나면) 영속성 컨텍스트를 종료 (플러시 호출하지 않고 바로 종료)
  • 단점
    • OSIV를 적용하면 같은 영속성 컨텍스트를 여러 트랜잭션이 공유 가능
    • 프리젠테이션 계층에서 엔티티를 수정하고나서 비즈니스 로직을 수행하면 엔티티가 수정될 수 있다.
    • 프리젠테이션 계층에서 지연로딩에 의한 SQL이 실행되기 때문에 성능 튜닝 시에 확인할 부분이 넓다.

0개의 댓글