OSIV

2024. 8. 3. 14:46Spring Boot

바로 필요 없는 데이터에 Proxy를 넣어두는 Lazy Loading
성능을 위해 쓰는 게 좋다지만 

강제 초기화니 DTO니 불편해 보인다

 

그래서 OSIV(Open Session in View) 가 있다.

 

이는 데이터 베이스 세션을 View까지 가지고 가서
Lazy Loading 문제를 해결하기 위한 방안 중 하나이다.

기본적으로 사용함으로 설정 되어 있으며 사

용하기 싫으면 application.properties에서 사용 않함을 추가해야 한다.

 

사용하는 경우

spring.jpa.open-in-view=true 

 

https://gracelove91.tistory.com/100

 

안 하는 경우

spring.jpa.open-in-view=false

 

https://gracelove91.tistory.com/100

 

 

다만 영속성 컨텍스트의 변화 감지의 기능은 지원하지 않는다

 

 

간단한 예시로

package com.example.demo.mySQL;


import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.util.ArrayList;
import java.util.List;

@Entity
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@Table(schema = "sqlEntity")
public class sqlEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column
    private String title;

    @Column
    private String data;

    @OneToMany(mappedBy = "parent", cascade = CascadeType.REMOVE, fetch = FetchType.LAZY)
    private List<sqlChild> childs = new ArrayList<>();

    sqlEntity(String title, String data) {
        this.title = title;
        this.data = data;
    }
}

 

 

package com.example.demo.mySQL;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class mySQLService {

    @Autowired
    private final mySQLRepository repo;

    public List<sqlEntity> all_data() {
        return repo.findAll();
    }
    
    public sqlEntity get_data(Long id) {
        return repo.findById(id).get();
    }

}

 

 

package com.example.demo.mySQL;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import java.util.List;
@Controller
@RequestMapping("/mysql")
public class mySQLController {
    
    @Autowired
    mySQLService service;
    

    //Lazy
    @RequestMapping(method = RequestMethod.GET)
    public String all_data2(Model model) {

        List<sqlEntity> list = service.all_data();

        model.addAttribute("testList", list);

        return "db/mySQLBoard";
    }

    //Lazy
    @RequestMapping(path = "/{id}", method = RequestMethod.GET)
    public String detail_data(@PathVariable Long id, Model model) {
        
        sqlEntity dto = service.get_data(id);

        model.addAttribute("detail", dto);
        model.addAttribute("childList", dto.getChilds());

        return "db/mySQLdetail";
    }
}

 

이런 식으로 Service단에서 강제초기화나 DTO를 사용하지 않고

Controller에서 Model에 데이터를 보내거나 get 메소드로 Lazy Loading된 Child를 불러오면 된다.

 

이는 OSIV가 

데이터 베이스 세션을 Controller, View까지 열어두어서 Proxy값을 초기화 할 수 있기 때문이다.

 

물론 사용에 주의해야 할 점도 있다.

 

1. 성능 문제

데이터 베이스 세션이 요청 전체의 생명 주기 동안 열려 있음

즉 데이터 베이스와 서버의 연결을 오래 유지해서 성능 저하를 초래할 수 있음

 

.2. 잘못된 설계 유도

엔티티를 View까지 전달해서 데이터의 수정 가능성이 생기고

계층 간의 경계를 흐릿하게 만들어 유지보수성을 저하시킴

 

3. 트랜잭션 관리

엔티티 변경 사항이 데이터베이스에 반영되기 위해서는 트랜잭션 경계 내에서 변경이 이루어져야 함

OSIV는 지연 로딩 문제를 해결하지만, 트랜잭션 경계를 관리하지는 않음

따라서 트랜잭션을 명확히 설정해야 함

 

 

 

 

 

그리고 결정적으로 No Session같은 에러가 나오며 동작을 하지 않는 경우도 있는데

이는 Spring Security와 호환성 문제로

보안 설정이 OSIV와 충돌해서 동작을 하지 않는 경우가 있음

 

'Spring Boot' 카테고리의 다른 글

Redis Cache  (0) 2024.10.11
WebMVC와 WebFlux를 동시 사용 할 경우 WebSocket  (0) 2024.08.14
@Transactional 과 영속성  (0) 2024.08.02
Lazy Loading  (0) 2024.07.31
Spring AOP  (0) 2024.07.10