본문 바로가기
JPA

JPA OSIV

by 이상한나라의개발자 2024. 1. 31.

JPA의 OSIV(Open Session In View) 영속성 컨텍스트를 뷰 렌더링이 완료될 때까지 유지하는 전략입니다. 웹 어플리케이션에서 데이터베이스 트랜젹션을 뷰 렌더링 전까지 열어두는 패턴입니다. ( API 일경우는 클라이언트에게 응답 완료시까지 )

 

일반적으로 JPA는 트랜잭션 범위 내에서 영속성 컨텍스트를 유지합니다. 즉, 트랜잭션이 커밋되거나 롤밸될 때 영속성 컨텍스트도 닫힙니다. 그러나 OSIV를 사용하면 트랜잭션이 유지되므로 뷰가 렌더링될 때까지 영속성 컨텍스트를 유지하게 됩니다.

 

예를 들어 OSIV 사용하면 화면에서 지연로딩을 사용하여 데이터를 렌더링할 수 있습니다. 다만, OSIV를 사용할 때 주의해야 할 점은 장기간의 트랜잭션을 유지하게 되면 데이터베이스 커넥션 리소스가 반환되지 않는 문제가 있을 수 있습니다. 

예를 들어서 컨트롤러에서 외부 API를 호출하면 API 대기 시간 만큼 커넥션 리소스를 반환하지 못하고 유지해야 합니다.

 

OSIV 의 장점 

  1. 지연로딩 문제 해결 : 뷰 렌더링 시점에 트랜잭션이 유지 되므로, 뷰에서 지연로딩된 데이터를 로딩할 수 있습니다.
  2. 간편한 데이터 접근 : 뷰에서 엔티티에 접근할 때 추가적인 데이터베이스 쿼리를 수행하지 않아도 되기 때문에 편리하게 데이터에 접근할 수 있습니다.
  3. 트랜잭션 경계 확장 : 트랜잭션을 뷰 렌더링 까지 확장하므로, 한 요청 내에서 여러 서비스 메소드를 호출하는 경우 트랜잭션 경계를 다루기가 쉬워집니다.

 

OSIV 단점

  1. 데이터베이스 커넥션 리소스 사용 : OSIV로 인해 트랜잭션이 뷰 렌더링까지 유지되므로, 데이터베이스 커넥션 리소스가 오랜 시간동안 사용될 수 있습니다. 이는 성능 및 리소스 사용 측면에서 좋지 않습니다.
  2. 보안문제 : 트랜잭션을 뷰 렌더링 까지 연장하면서, 뷰에서 불필요한 데이터에 접근할 수 있는 보안 문제가 발생할 수 있습니다.
  3. 복잡성 증가 : OSIV를 사용하면 트랜잭션의 범위가 확장되므로 코드의 복잡성이 증가할 수 있습니다.

이러한 문제로 인해 일반적으로 OSIV를 사용하지 않는 경향이 있습니다.

 

예시 코드

아래 코드는 OSIV 기능을 제외한 상태로 코드를 작성한 예시 입니다. JPA는 기본적으로 OSIV 기능이 true로 설정 됩니다.

application.yml 파일에서 open-in-view: off 로 설정합니다.

 

OSIV OFF

 

  jpa:
    hibernate:
      ddl-auto: create
    properties:
      hibernate:
        format_sql: true
        default_batch_fetch_size: 100
    open-in-view: off

 

 

예시 코드는 학생과, 학과로  N - 1 관계입니다. 학생은 한 학과에 소속될 수 있습니다. 

아래 controller 코드에서 student entity를 지연로딩으로 데이터를 조회하고 있습니다. 이때 osiv 기능을 사용하지 않으므로 에러가 발생하게 됩니다.

@RestController
@RequiredArgsConstructor
public class DepartmentController {

    private final DepartmentService departmentService;

    @GetMapping("/api/v1/department")
    public DepartmentEntity getDepartment() {

        DepartmentEntity department = departmentService.getDepartment(1L);

        department.getStudentEntityList().forEach(studentEntity -> {
            System.out.println("studentEntity = " + studentEntity);
        });

        return department;
    }
}

 

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class DepartmentService {

    private final DepartmentRepository departmentRepository;

    public DepartmentEntity getDepartment(Long departmentId) {
        return departmentRepository.findById(departmentId).orElseThrow();
    }
}

 

 

public interface DepartmentRepository extends JpaRepository<DepartmentEntity, Long> {
}

 

@Entity
@Table(name = "department")
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class DepartmentEntity extends BaseEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "department_id")
    private Long id;

    private String departmentName;

    private String departmentCode;

    @OneToMany(mappedBy = "departmentEntity")
    private List<StudentEntity> studentEntityList = new ArrayList<>();

    @Builder
    private DepartmentEntity(String departmentName, String departmentCode, List<StudentEntity> studentEntityList) {
        this.departmentName = departmentName;
        this.departmentCode = departmentCode;
        //this.studentEntityList = studentEntityList;
        this.studentEntityList = studentEntityList != null ? studentEntityList : new ArrayList<>();
    }

    public static DepartmentEntity createDepartment(String departmentName, String departmentCode, List<StudentEntity> studentEntityList) {
        return DepartmentEntity.builder()
                .departmentName(departmentName)
                .departmentCode(departmentCode)
                .studentEntityList(studentEntityList)
                .build();
    }
}

 

Request processing failed; nested exception is org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.student.domain.department.DepartmentEntity.studentEntityList, could not initialize proxy - no Session

 

OSIV를 on 으로 사용하게 변경하면 위 예시와는 반대로 controller에서 지연로딩 데이터를 조회할 수 있게 됩니다. 그 이유는 아래 그림처럼 트랜잭션의 범위가 확대되어 데이터베이스 커넥션 리소스를 여전히 가지고 있게 때문입니다.

 

OSIV ON

 

 

참고자료 : 자바 ORM 표준 JPA 프로그래밍 - 김영한 저

'JPA' 카테고리의 다른 글

Spring Data JPA  (0) 2024.03.08
JPA 조회 전략  (0) 2024.03.07
JPA Entity 설계시 베스트 프랙티스  (0) 2024.02.22
JPA Auditing  (0) 2024.01.30
JPA  (0) 2023.12.03