군만두의 IT 개발 일지

[스터디10] 12. 웹 애플리케이션과 영속성 관리 본문

학습일지/Java

[스터디10] 12. 웹 애플리케이션과 영속성 관리

mandus 2025. 10. 22. 12:29

목차

    13장. 웹 애플리케이션과 영속성 관리

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

    • 순수하게 J2SE 환경에서 JPA를 사용하면 개발자가 직접 엔티티 매니저를 생성하고 트랜잭션도 관리해야 한다.
    • 스프링이나 J2EE 컨테이너 환경에서 JPA를 사용하면 컨테이너가 제공하는 전략을 따라야 한다.

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

    스프링 컨테이너는 트랜잭션 범위의 영속성 컨텍스트 전략을 기본으로 사용한다.

    • 트랜잭션을 시작할 때 영속성 컨텍스트를 생성하고, 트랜잭션이 끝날 때 영속성 컨텍스트를 종료한다.
    • 같은 트랜잭션 안에서는 항상 같은 영속성 컨텍스트에 접근한다.
    • @Transactional 어노테이션이 있으면 메소드를 실행하기 직전에 스프링의 트랜잭션 AOP가 먼저 동작한다.

    트랜잭션이 같으면 같은 영속성 컨텍스트를 사용한다.

    • 다양한 위치에서 엔티티 매니저를 주입받아 사용해도 트랜잭션이 같으면 항상 같은 영속성 컨텍스트를 사용한다.

    트랜잭션이 다르면 다른 영속성 컨텍스트를 사용한다.

    • 여러 스레드에서 동시에 요청이 와서 같은 엔티티 매니저를 사용해도 트랜잭션에 따라 접근하는 영속성 컨텍스트가 다르므로 멀티 스레드 상황에 안전하다.

    13.2 준영속 상태와 지연 로딩

    스프링이나 J2EE 컨테이너는 트랜잭션 범위의 영속성 컨텍스트 전략을 사용하므로, 트랜잭션이 없는 프레젠테이션 계층에서 엔티티는 준영속 상태다. 따라서 변경 감지와 지연 로딩이 동작하지 않는다.

    • 트랜잭션은 보통 서비스 계층에서 시작하므로 서비스 계층이 끝나는 시점에 트랜잭션이 종료되면서 영속성 컨텍스트도 종료된다.
    • 준영속 상태의 문제는 지연 로딩이 동작하지 않는다는 점이다. 이때 지연 로딩을 시도하면 LazyInitializationException이 발생한다.

    준영속 상태의 지연 로딩 문제 해결 방법

    1. 뷰가 필요한 엔티티를 미리 로딩해두는 방법
      1. 글로벌 페치 전략 수정
      2. JPQL 페치 조인
      3. 강제로 초기화
    2. OSIV를 사용해서 엔티티를 항상 영속 상태로 유지하는 방법

    13.2.1 글로벌 페치 전략 수정

    • 가장 간단한 방법은 글로벌 페치 전략을 지연 로딩에서 즉시 로딩으로 변경하는 것이다.
    • 단점:
      • 사용하지 않는 엔티티를 로딩한다.
      • N+1 문제가 발생한다.

    13.2.2 JPQL 페치 조인

    • JPQL을 사용하여 필요한 엔티티를 미리 로딩할 수 있다.
    • 페치 조인을 사용하면 SQL JOIN을 사용해서 연관된 엔티티를 함께 조회하므로 N+1 문제가 발생하지 않는다.
    • 단점:
      • 무분별하게 사용하면 리포지토리 메소드가 증가할 수 있다.
      • 프레젠테이션 계층과 데이터 접근 계층 간에 의존관계가 증가한다.

    13.2.3 강제로 초기화

    • 영속성 컨텍스트가 살아있을 때 프레젠테이션 계층이 필요한 엔티티를 강제로 초기화해서 반환하는 방법이다.
    • 엔티티를 초기화하려면 연관된 엔티티의 값을 호출하면 된다.
    • 단점: 프레젠테이션 계층이 필요한 엔티티에 따라 서비스 계층의 로직을 변경해야 한다.

    13.2.4 FACADE 계층 추가

    • 프레젠테이션 계층과 서비스 계층 사이에 FACADE 계층을 하나 추가하는 방법이다.
    • FACADE 계층에서 프레젠테이션 계층이 필요로 하는 엔티티를 미리 초기화한다.
    • 서비스 계층과 프레젠테이션 계층 사이의 논리적인 의존성이 분리할 수 있다.
    • 단점: 중간에 계층이 하나 더 추가된다.

    13.2.5 준영속 상태와 지연 로딩의 문제점

    • 뷰 개발에 필요한 엔티티를 미리 초기화하는 것은 오류가 발생할 가능성이 높다.
    • 모든 문제는 엔티티가 프레젠테이션 계층에서 준영속 상태이기 때문에 발생한다.
    • 영속성 컨텍스트를 뷰까지 열어두면 뷰에서도 지연 로딩을 사용할 수 있다. (OSIV)

    13.3 OSIV

    OSIV(Open Session In View)는 영속성 컨텍스트를 뷰까지 열어둔다. 영속성 컨텍스트가 살아있으면 엔티티는 영속 상태로 유지되고, 따라서 뷰에서도 지연 로딩을 사용할 수 있다.

    13.3.1 과거 OSIV: 요청 당 트랜잭션

    • 가장 단순한 구현 방법은 요청이 들어오자마자 서블릿 필터나 스프링 인터셉터에서 트랜잭션을 시작하고 요청이 끝날 때 트랜잭션을 종료하는 것이다.
    • 이렇게 하면 영속성 컨텍스트가 프레젠테이션 계층까지 살아있으므로 뷰에서도 지연 로딩을 사용할 수 있다.
    • 단점:
      • 프레젠테이션 계층에서 엔티티를 변경할 수 있다.
      • 프레젠테이션 계층에서 데이터를 변경하고 실제 데이터베이스에 반영이 되면 애플리케이션을 유지보수하기 힘들다.

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

    스프링 프레임워크가 제공하는 OSIV는 비즈니스 계층에서만 트랜잭션을 유지한다.

    • 영속성 컨텍스트를 프레젠테이션 계층까지 유지한다.
    • 프레젠테이션 계층에는 트랜잭션이 없으므로 엔티티를 수정할 수 없다.
    • 프레젠테이션 계층에는 트랜잭션이 없지만 트랜잭션 없이 읽기를 사용해서 지연 로딩을 할 수 있다.
    • 단점:
      • OSIV를 사용하면 같은 영속성 컨텍스트를 여러 트랜잭션이 공유할 수 있다.
      • 프레젠테이션 계층에서 엔티티를 수정하고나서 비즈니스 로직을 수행하면 엔티티가 수정될 수 있다.
      • 프레젠테이션 계층에서 지연 로딩에 의한 SQL이 실행된다.
    •  

    13.4 너무 엄격한 계층

    • OSIV를 사용하기 전에는 프레젠테이션 계층에서 사용할 지연 로딩된 엔티티를 미리 초기화해야 했다.
    • 초기화는 영속성 컨텍스트가 살아있는 서비스 계층이나 FACADE 계층이 담당했다.
    • OSIV를 사용하면 영속성 컨텍스트가 프레젠테이션 계층까지 살아있으므로 미리 초기화할 필요가 없다.

     

    ✔️ 복습하기
    1. 스프링 컨테이너의 기본 영속성 컨텍스트 전략은?
    2. 트랜잭션이 같으면 영속성 컨텍스트는 어떻게 되는가?
    3. 준영속 상태에서 지연 로딩을 시도하면?
    4. OSIV란?

     

    이 글은 『 자바 ORM 표준 JPA 프로그래밍』 책을 학습한 내용을 정리한 것입니다.
    Comments