[ TIL ] Open Session In View

charco·2021년 10월 19일
0

나도TIL

목록 보기
51/55
post-custom-banner

영속성 컨텍스트와 트랜잭션

영속성 컨텍스트는 트랜잭션과 함께 살고 죽는다.
트랜잭션은 비즈니스 로직을 담고 있는 서비스 계층에서 관리한다.
따라서 컨트롤러에서는 영속성 컨텍스트가 존재하지 않는다.
하지만 컨트롤러에서도 영속성 컨텍스트가 필요할 때가 있다.
대표적으로는 지연로딩을 써야 할 때이다.

// 컨트롤러 클래스

Member member = memberService.findOne(1L);
member.getOrders().get(0) // 예외 발생

그러나 영속성 컨텍스트가 존재하지 않는 채로 지연로딩을 한다면
org.hibernate.LazyInitializationException 예외가 던져질 것이다.

과거의 OSIV

OSIV 는 Open Session In View 의 약자다.
말 그대로 뷰까지 세션을 열어놓는다는 뜻인데
컨트롤러까지 트랜잭션을 열어놓는다는 것이다.
그 말은 즉슨, 사용자의 요청이 시작되고 끝날때까지 트랜잭션이 유지되고,
영속성 컨텍스트 또한 유지된다는 것이다.
그러면 위의 문제는 해결된다.

// 컨트롤러 클래스 (트랜잭셩과 영속성 컨텍스트 둘다 살아있다.)
Member member = memberService.findOne(1L);
member.getOrders().get(0) // 조회됨.

그런데 다른 문제가 있다.
컨트롤러에서 사용자에게 보여주기만을 위해 엔티티를 수정한다면?

// 컨트롤러 클래스 (트랜잭션과 영속성 컨텍스트 둘다 살아있다.)
Member member = memberService.findOne(1L);
member.setPassword("비밀임");

model.addAttribute("member", member);

무슨 일이 일어날까?....

그렇다. 사용자의 비밀번호가 "비밀임"으로 바뀌어 버린다.
요청이 끝나면 엔티티 매니저의 flush()가 호출된다.
변경감지가 일어난다.
쓰기 지연 SQL 저장소의 쿼리들이 날아가고...
트랜잭션은 커밋되어버린다.

이건 정말 큰 문제다. 그래서 스프링은 좀 다른 OSIV를 제공한다.


스프링의 OSIV

스프링의 OSIV는 위의 OSIV와 같지만
트랜잭션만 비즈니스 로직에서 동작한다.
요청과 생명주기가 같은건 오직 영속성 컨텍스트다.

따라서 컨트롤러에서 조회는 가능하지만 수정은 불가능하다.
왜냐하면 트랜잭션이 없기 때문이다.

트랜잭션 없이도 영속성 컨텍스트를 통한 조회는 가능하다.

// 컨트롤러 클래스 (영속성 컨텍스트만 살아있다.)
Member member = memberService.findOne(1L);
member.getOrders().get(0) // 조회됨.

하지만 주의할 점이 있다.
다음의 코드를 보며 생각해보자.

// 컨트롤러 클래스 (영속성 컨텍스트만 살아있다.)
Member member = memberService.findOne(1L);
member.setPassword("비밀임");

memberService.doSomething(); // 트랜잭션을 시작하는 메서드

model.addAttribute("member", member);

무슨 일이 일어날까?
똑같은 문제가 발생한다.
왜냐하면 영속성 컨텍스트 안에서 변경했기 때문이다.
트랜잭션이 있든 없든, 영속성 컨텍스트가 관리하는 엔티티가 변경됐다.
그 이후 트랜잭션이 시작되고 커밋된다.
커밋되기 전에 flush()가 발생한다.
결국 변경감지가 일어난다.

이럴때는 아래와 같이 트랜잭션 작업을 먼저 끝내고 엔티티를 변경하면 된다.

// 컨트롤러 클래스 (영속성 컨텍스트만 살아있다.)

memberService.doSomething(); // 트랜잭션을 시작하는 메서드

// 트랜잭션이 끝나고 엔티티를 변경한다. 아무런 일도 일어나지 않는다.
Member member = memberService.findOne(1L);
member.setPassword("비밀임");

model.addAttribute("member", member);
profile
아직 배우는 중입니다
post-custom-banner

0개의 댓글