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

안지혁님의 프로필 이미지

작성한 질문수

실전! Querydsl

스프링 데이터 JPA 리포지토리로 변경

@Transaction에 대해서 질문드드립니다.

작성

·

821

1

안녕하세요? 강사님. 항상 좋은 강의 잘 보고 있습니다.

이번강의를 보면서 에러가 발생하였습니다.

Member member = new Member("member1", 10);
memberRepository.save(member);

Member findMember = memberRepository.findById(member.getId()).get();
assertThat(findMember).isEqualTo(member);

assertThat부분에서 

 <"Member(id=1, username=member1, age=10) (Member@1b444b5)">

to be equal to:

 <"Member(id=1, username=member1, age=10) (Member@5a1a20ae)">

but was not.

Expected :Member(id=1, username=member1, age=10)

Actual   :Member(id=1, username=member1, age=10)

이러한 에러가 발생했습니다. 알고보니 @Transaction 어노테이션을 선언을 안해서 그랬습니다.

member와 findMember의 메모리 주소가 달라서 에러가 발생한것 같은데 메모리가 주소가 왜 다른지 잘 이해가 안됩니다.

meber객체를 save 하면서 영속성 컨텍스트에 담기고 findMember는 영속성컨텍스트에 담겨있는 member인것이 아아니라 새로 select문을 날려서 디비에서 조회한 값이더라구요(

@Transactional이 없을 때  로그를 통해서 확인하였습니다) @Transactional을 선언 하고 save 후  em.flush(); em.clear();를 해준것과 같은 현상이 나더라구요.

@Transactional이 롤백외에도 어떠한 기능이 있길래 이러한 현상이 나타나는지 알고 싶습니다.

감사합니다.

답변 1

1

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

안녕하세요. 지혁님

JPA는 기본으로 트랜잭션 단위로 영속성 컨텍스트가 부여되고 사용됩니다.

트랜잭션을 선언하지 않으면 스프링 데이터 JPA가 리포지토리 코드 내부에서 트랜잭션을 별도로 사용합니다.

따라서 다음과 같이 동작합니다.

memberRepository.save(member); 트랜잭션 A, 영속성 컨텍스트A

memberRepository.findById(member.getId()).get(); 트랜잭션 B, 영속성 컨텍스트B

@Tx를 먼저 선언하고 테스트를 시작하면 트랜잭션이 전파되기 때문에 다음과 같이 동작합니다.

트랜잭션 Z

test()

memberRepository.save(member); 트랜잭션 Z, 영속성 컨텍스트Z

memberRepository.findById(member.getId()).get(); 트랜잭션 Z, 영속성 컨텍스트Z

관련해서 다음 링크를 참고해주세요^^

https://www.inflearn.com/questions/158967

감사합니다.