Spring으로 웹 애플리케이션을 실행하였을 때, 특별한 설정을 해주지 않으면 아래와 같은 경고가 출력되는 것을 확인할 수 있다.
이번 포스팅을 통해 해당 경고는 왜 출력되는 것이고, spring.jpa.open-in-view가 무엇인지에 대해서 정리하려고 한다.
2023-03-24 20:52:47.034 WARN 63885 --- [ restartedMain] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
Spring OSIV
spring OSIV는 영속성 컨텍스트를 뷰까지 열어둔다는 뜻이다.
*영속성 컨텍스트 : 엔티티를 영구 저장하는 환경을 말한다. 이를 통해 우리는 1차 캐시, 동일성 보장, 쓰기지연, 변경감지, 지연로딩 등 여러 이점을 얻을 수 있다.
우리는 Spring OSIV를 통해 영속성 컨텍스트의 이점 중 지연로딩이라는 이점을 얻을 수 있다.
실제 나의 경험을 바탕을 이야기하면, 프레젠테이션 계층과 서비스 계층을 나누어서 개발함에 있어서 OSIV를 모르기전에는 컨트롤러에서 필요한 데이터에 따라 의존적으로 서비스를 만들곤 했다. (컨트롤러 하나에 서비스 하나)
하지만 만일 OSIV가 설정되어 있다면, 프레젠테이션 계층(컨트롤러)에서 지연로딩을 사용하여 서비스 계층과 프레젠테이션 계층의 논리적 의존관계를 제거할 수 있다. (하나의 서비스를 여러 컨트롤러에 사용하고, 컨트롤러의 필요에 따라 지연로딩을 사용하여 필요한 데이터를 가져온다.)
위 그림을 보면 알 수 있듯이, 요청이 오면 영속성 컨텍스트가 생성되고, 응답을 하기 전까지 영속성 컨텍스트가 존재하기 때문에 프레젠테이션 계층(View, Controller)에서도 지연로딩이 가능하다.
하지만 프레젠테이션 계층에서는 영속성 컨텍스트 내 데이터 수정(변경감지)은 불가능하다.
- 트랜잭션이 끝난 이후에는 데이터를 변경하더라도 영속성 컨텍스트가 종료될 때 flush가 되지 않는다.
지금까지 내용을 정리해 보면, 우리는 Spring OSIV를 사용함으로써 아래의 이점을 가져올 수 있다.
- 프레젠테이션 계층에서 지연로딩을 통해 원하는 데이터를 가져올 수 있다.
- 실수로 프레젠테이션 계층에서 데이터를 변경하더라도 실제 데이터베이스에는 반영되지 않는다.
하지만 이러한 이점이 있음에도 불구하고, 우리에게 경고를 주는 이유는 있을 것이다.
Spring OSIV를 사용함으로써, 우리가 주의해야 할 점이 존재한다.
1. 프레젠테이션 계층에서 지연로딩으로 인해 추가적인 SQL문이 발생한다.
- 이로 인해 성능 튜닝에 있어서 비스니스 로직을 담당하는 서비스 계층 외 프레젠테이션 계층도 확인해야 하는 단점이 있다.
- 성능 튜닝 시 확인해야 하는 범위가 넓어진다.
2. 프레젠테이션 계층에서 엔티티를 수정한 직후에 다른 트랜잭션이 시작하면 문제가 발생한다.
- 영속성 컨텍스트는 여러 트랜잭션이 공유할 수 있기 때문에, 불필요한 데이터 변경사항을 다른 트랜잭션이 접근할 수 있다.
3. DB 커넥션이 낭비될 수 있다.
- 영속성 컨텍스트를 프레젠테이션 계층까지 열어둠에 따라, DB 커넥션도 요청이 끝날 때까지 유지된다.
- 이는 DB 커넥션 부족 현상을 초래할 수 있어 트래픽이 많거나 성능이 중요한 서버에서는 큰 성능 저하 문제를 일으킬 수 있다.
- 실제 DB 커넥션을 관리하는 것은 매우 중요하다.
- 실무에서는 DB 커넥션을 효율적으로 사용하는 것이 대용량 트래픽을 처리하는 데에 매우 중요한 요소 중 하나이기 때문에 OSIV를 사용하지 않는다고 한다.
따라서 OSIV를 사용하는 이점보다 치명적인 단점이 존재하기 때문에, Spring에서도 개발자에게 경고를 주고, 실제 실무에서도 OSIV를 사용하지 않고 개발하는 것 같다.
하지만, 요청이 많지 않는 관리자 페이지와 같은 경우에는 지연로딩의 이점을 살려 OSIV를 사용한다고 한다.
아래와 같이 application 설정을 통해서 Spring OSIV 설정을 OFF 할 수 있다.
- application.properties
spring.jpa.open-in-view:false
- application.yml
spring:
jpa:
open-in-view: false
OSIV를 사용하지 않음으로써, DB 커넥션 이슈는 발생하지 않을 수 있다.
하지만, 이제는 view에 렌더링 할 데이터를 트랜잭션 내에서 모두 지연로딩으로 가져와야 한다. 트랜잭션 내 로직의 복잡성을 관리하기 위해서 커멘드와 쿼리 분리하는 방법이 있다.
예를 들어, 게시물 관련 서비스 계층 코드를 아래와 같이 분리하는 것이다.
- PostService.java
- 비즈니스 로직 담당
- 특정 엔티티를 CRUD 하는 것을 담당하기 때문에, 성능 문제나 발생하지 않고 추후에 변경될 가능성도 적다.
- PostQueryService.java
- 화면에 렌더링 하기 위해 필요한 로직 담당
- 자주 변경되고, 복잡한 화면을 렌더링하기 위해서 성능 최적화가 중요하다.
다음과 같이 관심사로 서비스 계층을 분리함으로써, 유지보수성과 성능개선에 있어서 이점을 가져올 수 있다.
Spring OSIV라는 개념을 대충 넘기지 말고, 서비스의 특징에 따라서 OSIV를 사용할지, 사용하지 않을지 결정하고 그에 맞게 개발을 하는 것이 중요하다고 생각한다.
참고문헌
- [자바 ORM 표준 JPA 프로그래밍:스프링 데이터 예제 프로젝트로 배우는 전자정부 표준 데이터베이스 프레임워크] 도서
'개발 > Spring' 카테고리의 다른 글
JWT (2) 스프링에서 JWT 사용하기 (0) | 2023.05.31 |
---|---|
[Spring] 벌크 연산 (0) | 2023.05.15 |
[Spring] RestTemplate 싱글톤 등록 및 Connection Pool 설정 (0) | 2023.05.14 |
[Spring] 간편 결제 기능 팩토리 클래스 적용하기 (0) | 2023.05.02 |
[Spring] 동일한 클래스 내에서 내부 메서드 호출시 @Transactional 적용 안되는 이슈 (0) | 2023.04.02 |