[JPA] OSIV(Open Session In View)

Junseo Kim·2021년 7월 18일
0

Spring

목록 보기
5/7
post-thumbnail

영속성 컨텍스트는 트랜잭션 당 하나가 생성된다. 따라서 @Transactional을 붙여주지 않으면, db 관련 로직이 여러개 있을 때 각각 영속성 컨텍스트가 생성된다.

그래서 실제로 아래와 같은 코드가 있을 때, @Transcational이 붙어있지 않아 save 메서드 실행 후, changeName을 해도 foundUser의 이름은 max가 아닌 air가 되어야한다고 생각했다.

public void update() {
    User user = userRepository.save(new User("air"));
    user.changeName("max");

    User foundUser = userRepository.findById(user.getId())
                                   .orElseThrow(IllegalArgumentException::new);

    System.out.println("foundUser = " + foundUser.getName());
}

그러나 출력 결과를 보면 foundUser의 이름은 max였다. save가 이뤄질 때 영속성 컨텍스트가 끝나기 때문에 changeName을 해도 반영이 되지 않아야했는데 왜 이름이 바뀌었을까?

아무리 고민해봐도 모르겠어서 제이슨에게 물어봤는데 OSIV라는 키워드를 주셨다.

결론부터 말하면 jpa 사용시 기본적으로 OSIV 옵션이 true이기 때문에 일어나는 현상이었다. application.properties에서 spring.jpa.open-in-view=false 설정을 해주면 위의 update 메서드 실행시 foundUser의 이름이 max가 아닌 air로 출력된다.

위의 예시에서 osiv를 켰었을때 가져온 값은 db에서 가져온게 아니고 영속성 컨텍스트에서 가져온 값이다. 실제로 DB에 접속해보면 값이 air로 나온다.

OSIV란?

그럼 OSIV가 무엇일까? OSIV는 영속성 컨텍스트를 뷰까지 열어두는 기능이다. 따라서 엔티티도 계속 영속 상태로 관리된다.

따라서 위의 경우에 @Transactional이 없었지만 user는 계속 영속 상태로 관리되기 때문에 changeName 메서드가 효력이 있었던 것이다.(실제 db에 반영된건 아니다. 뒤에 @Transactional 이 붙은 메서드 호출시는 쓰기지연 저장소에 쓰여있던 쿼리가 날라가서 실제 db에도 반영된다.)

osiv 켜져있고 @transactional 없을때 -> 영속성 컨텍스트가 열려있어서 엔티티를 변경시켰을때 영속성컨텍스트에는 반영됨. 실제로 바뀌는것은아님(db에는 반영안됨. 쓰기 지연 저장소에 써놓음)

osiv 꺼져있고 @transactional 없을때 -> 영속성 컨텍스트 자체에도 반영안됨.

동작 방식

1) 클라이언트의 요청이 들어오면 영속성 컨텍스트가 생성된다.
2) 그 후, @Transactional이 붙어있는 메서드가 실행될 때 만들어 놓은 영속성 컨텍스트를 가지고 와 트랜잭션 처리를 시작한다.
3) 이 트랜잭션이 끝나면 플러시와 커밋이 일어난다.

4) 여기서 OSIV가 false라면 영속성 컨텍스트가 종료되지만, OSIV가 true라면 영속성 컨텍스트가 계속 살아있다.

단점

OSIV가 true인 경우 데이터베이스 커넥션이 계속 유지되므로 커넥션 비용이 낭비 될 수 있다는 단점이 있다.

reference

OSIV(Open Session In View)

0개의 댓글