글 요약은
Member와 Post를 만들어주기
@Getter
@NoArgsConstructor
@Entity
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY,optional = false)
private Member member;
public Post(Member member){
this.member = member;
}
}
@Entity
@NoArgsConstructor
@Getter
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String userName;
@OneToMany(mappedBy = "member",fetch = FetchType.LAZY)
private List<Post> posts = new ArrayList<>();
public Member(String userName){
this.userName = userName;
}
}
리포지토리는
public interface MemberRepository extends JpaRepository<Member,Long> {
}
public interface PostRepository extends JpaRepository<Post,Long> {
}
서비스는 다음과 같다.
@RequiredArgsConstructor
@Service
public class MemberService {
private final MemberRepository memberRepository;
private final PostRepository postRepository;
@Transactional
public void deleteMemberById(Long id){
Member member = memberRepository.findById(id).orElseThrow();
try{
memberRepository.delete(member);
}catch (DataIntegrityViolationException e){
throw new IllegalArgumentException("여기");
}
}
}
테스트코드는 다음과 같다.
@SpringBootTest
@RequiredArgsConstructor
@TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL)
public class Test1 {
private final MemberRepository memberRepository;
private final PostRepository postRepository;
private final MemberService memberService;
@Test
public void 트랜잭션(){
Member member = memberRepository.save(new Member("sung_jee"));
postRepository.save(new Post(member));
Long memberId = member.getId();
Assertions.assertThatThrownBy(()->memberService.deleteMemberById(memberId))
.isInstanceOf(IllegalArgumentException.class);
}
}
테스트는 실패한다.
이유는 다음과 같다
service 메소드인
deleteMemberById에서 Transaction이 시작된다.!
이때 memberRepository.delete(member)에서
delete함수는 다음처럼 @Transaction이 default값으로 설정되어있다.
기본값인 Required는 부모 트랜잭션있으면 그거 쓰게 된다.
아까 service에서 @Transacional걸어줬으니
이 delete 메소드는 service의 함수랑 생명주기가 같아지게 된다.
이때 쓰기지연 저장소에 기록되고
transcation이 끝날 때 쯤 나가는 실제 쿼리가 나가지 않게 된다.
다음 service 메소드가 끝날 때 나가게 됨..
그래서 DataInegrityViolationException을 받지 못한채로
서비스 함수가 종료될 때 쯤 저 exception이 발생되어
테스트가 실패하게된다.
그래서 서비스 함수위의 @Transactional을 빼주게 되면
delete 함수내에서만 Transaction이 생성 및 진행되어
try catch 내에서 DataInegrityViolationException을 받을 수 있게 된다.