인프런 커뮤니티 질문&답변

relate16님의 프로필 이미지
relate16

작성한 질문수

스프링 DB 2편 - 데이터 접근 활용 기술

트랜잭션(readOnly=true)와 스냅샷의 관계

작성

·

553

·

수정됨

1


[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? (/아니오)
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (/아니오)
3. 질문 잘하기 메뉴얼을 읽어보셨나요? (/아니오)

[질문 내용]

이번 질문 내용을 정리해보니 좀 길어서 미리 좀 죄송합니다..

...질문은 1개입니다. 스냅샷과 @Transactional(readOnly=true)의 관계 질문입니다.

질문 내용은 다음과 같습니다.


스프링 트랜잭션 이해/트랜잭션 옵션 소개 11:04 쯤 보면

JPA는 읽기 전용 트랜잭션(@Transactional(readOnly=true))일 경우

커밋 시점에 플러시를 호출하지 않는다. ... 추가로 변경이 필요 없으니 변경 감지를 위한 스냅샷 객체도 생성하지 않는다.

라고 들었는데 이때 갑자기 스냅샷의 관계에 대해 헷갈려 질문해봅니다.

말 그대로

MemberService.class 에 있는

@Transactinal(readOnly=true)

findMemberById()

로 find 해왔는데 스냅샷이 생성이 안되면

Member findMember = memberService.findMemberById(memberId);

findMember.setUsername("변경된 username");

의 코드가 동작했을 때 변경이 안된다는 건데

그러면 되게 난감한 상황인 것 같아

말이 안돼서 다시 생각해보았습니다.

 

그래서 제가 생각해보고 시도해봤는데,

@Transactional(readOnly=true) findMember() 메서드 내에서는

스냅샷이 생성이 안되고

Member findMember = memberService.findMember(memberId); 에서

findMember는 스냅샷 생성이 되어 있는 것이겠다가 결론입니다.

 

결론을 내보긴 했지만

jpa를 배웠을 때

find의 경우

DB에서 조회해 오는 순간 스냅샷이 생성되어 있는 것으로 이해했어서

왜 memberService.findMember() 에서의 트랜잭션이 commit 되고 나서

스냅샷이 생성되는지는 모르겠네요.

트랜잭션 readOnly=true일 경우 로직을 그렇게 작동하게 해놓은 건가..

 

어쨌든.. 제 결론이 맞을까요 ?

 

아래는 실험해본 코드와

생각해서 정리해본 1차캐시 이미지 입니다.

질문1.pngfind만 했을 경우 혹시 안에 변경감지가 되는지 보려고

member.setUsername("1111"); 을 해봤습니다.

지금 생각해보니

(readOnly=true)라서 flush가 일어나지 않아 update 쿼리가 당연히 안 나가겠지만

확인차 해봤다고 봐주시면 될 것 같습니다.

// flush() 때문에 update 쿼리가 안 나가는 거면 내부에 스냅샷이 있을 수도 있겠네요.

 

어쨋든 이 결과 생각한 1차 캐시 및 스냅샷 이미지입니다.

질문2.png트랜잭션 시작, 종료 사이에 스냅샷이 비워져 있는지 확실하진 않아서

저게 맞는 지가 핵심 질문입니다.

 

만약 비워져 있는 게 맞다면,

부가적으로 따라오는 의문은 다음과 같습니다.

질문3.pngchangeMemberUsername() 메서드를 호출했을 때

1차 캐시 및 스냅샷은 어떻게 동작하는가 입니다.

일반적으로 find를 해온 후

데이터를 변경하는 JPA이기 때문에

@Transactional(readOnly=true) findMemberById() 로 들고온 결과는

반드시 스냅샷이 있어야 된다는 게 제 생각이기 때문에

다음과 같이 동작할 거라고 결론을 지어봤습니다.

질문4.png이렇게 스냅샷이 동작하는 게 맞을까요 ?

 

여기까지 읽어주셔서 정말 정말 감사합니다.

 

 

 

답변 1

2

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. relate16님

JPA에서 스냅샷의 존재 이유는 데이터를 변경할 때만 필요합니다.

왜냐하면 데이터를 변경했을 때 최초 상태(스냅샷)과 변경된 상태를 비교할 수 있어야 하기 때문입니다.

트랜잭션을 읽기 전용으로 사용하는 경우에는 데이터를 변경하지 않는 목적으로 조회하게 됩니다.

따라서 JPA 입장에서 읽기 전용 트랜잭션의 경우 데이터를 변경하지 않기 때문에 스냅샷이 필요하지 않습니다.(읽기 전용 트랜잭션의 경우 트랜잭션이 끝나도 JPA를 플러시 하지 않습니다.)

참고로 과거 버전에서는 스프링 트랜잭션과 무관하게 스냅샷을 항상 만들었는데, 최신 버전에서는 최적화가 되어서, 읽기 전용 트랜잭션에서는 스냅샷을 만들지 않습니다.

감사합니다.

relate16님의 프로필 이미지
relate16
질문자

아 뭔가 이해될 것 같습니다.

마지막 그림처럼 트랜잭션 읽기 전용으로 가져온 객체를 데이터 변경했는데 업데이트 쿼리가 날아간 건 스프링 최신 버전이 아니어서 그럴 수 있는 거고

읽기 전용으로 가져온 객체를 변경하면

업데트 쿼리가 안나가야 정상이라는 거죠?

 

그 전에 말씀하신대로 읽기 전용 으로 가져온 객체는 데이터 변경하는 용도로 쓰는 게 아니니 변경할 이유도 없는 거지만요.

항상 감사합니다 :)

김영한님의 프로필 이미지
김영한
지식공유자

네 생각하신 내용이 맞습니다.

감사합니다.

relate16님의 프로필 이미지
relate16

작성한 질문수

질문하기