저번 글에서 짧게 이야기 했던 부분을 다시 이야기 해보기 위해서 먼저 코드를 보여주고, 궁금한 점을 이야기 해보겠다.
UpdateMentoInfoHandler.class
@Component
@RequiredArgsConstructor
public class UpdateMentoInfoHandler {
private final MentoService mentoService;
public void execute(MentoInfoUpdateRequestDTO mentoInfoUpdateRequestDTO, Long Id) throws IOException {
mentoService.updateMentoInfo(mentoInfoUpdateRequestDTO, mentoService.findMento(Id));
}
}
MentoService.class
@Transactional
public void updateMentoInfo(MentoInfoUpdateRequestDTO updateRequest, Mento mento) {
if (updateRequest.getIntroduction() != null) {
mento.updateIntroduction(updateRequest.getIntroduction());
}
if (updateRequest.getCompany() != null) {
mento.updateCompany(updateRequest.getCompany());
}
if (updateRequest.getMajor() != null) {
Major.getMajor(updateRequest.getMajor().toString());
mento.updateMajor(updateRequest.getMajor());
}
}
저번 글에서 가지고 있던 궁금증이 해결되어서 즐거운 마음으로 있었으나, 또 다른 궁금증이 생겨서 부모 트랜잭션에 있는 @Transactional
어노테이션을 제거 해보았다.
나는 부모 트랜잭션을 제거하면, 같은 영속성 컨텍스트를 더 이상 공유하지 않기에 부모 메서드에서 영속성 컨텍스트에 저장했던 Mento 엔티티가 더 이상 Dirty Checking이 되지 않을 것이라고 생각했다…
그러나 여전히 Mento 엔티티가 Dirty Checking이 되는 것을 확인 할 수 있었다.
도대체 왜 Mento 엔티티가 Dirty Checking이 되는걸까?
답은 바로 OSIV였다.
그러면 OSIV가 뭐길래 이런 결과가 나왔는지 알아보자.
내가 카카오 테크 캠퍼스에서 강사님께 배웠던 OSIV의 개념이란 다음과 같다.
일반적으로 @Transactional
이 붙은 레이어(서비스)에서 트랜잭션이 시작되고, 서비스가 종료될 때, 트랜잭션이 종료되며, 이것은 open in view를 false로 설정한 것과 동일하다.
"Open in View"를 사용하는 경우도 마찬가지로 트랜잭션의 시작은 서비스이고, 트랜잭션의 종료도 서비스가 종료될 때 종료된다.
하지만 DB에 select할 수 있는 세션이 view에 렌더링될 때까지 유지된다. 이 기능을 켜두고, 엔티티를 컨트롤러에서 응답하는 순간 Lazy Loading으로 인해 예상치 못한 결과가 발생할 수 있다.
그러면 OSIV 옵션을 켜고, 끌 때 각각의 특징에 대해서 살펴보자.
OSIV = true
OSIV = true
→ Select(DB 커넥션, 세션)가 처음부터(Controller부터) 가능하고, 데이터 수정, 추가, 삭제등은 Service부터 가능하다.OSIV = true의 장점
OSIV = false
"Open in View"를 사용하는 경우 주의해야 할 점은 장기간 트랜잭션 유지로 인해 데이터베이스 리소스가 오랜 시간 동안 점유될 수 있으며, 불필요한 쿼리나 성능 문제가 발생할 수 있다. 따라서 "Open in View"를 사용할 때는 성능 측면과 리소스 관리에 유의하여 적절한 사용 방식을 선택해야한다
Spring boot는 OSIV가 기본적으로 true로 켜져있고, 해당 OSIV를 false로 지정하면 더 이상 더티 체킹이 되지 않는 것을 확인할 수 있었다.
감사합니다. 이런 정보를 나눠주셔서 좋아요.