Search
Duplicate

[Java] @Transaction 롤백 안되는 원인[프록시]

순서
6
날짜
2023/08/04
사람
상태
Done
오늘은 회사 동료분이 트랜잭션이 안되는 원인을 공유해줘서, 좋은 글이라 작성하게 되었다.
요청사항
회원 전체데이터를 일괄로 수정
수정도중 실패한다면 실패한 회원만 롤백
회원 수정 이력에는 실패와 성공에대한 데이터를 저장
구현 방법
일괄로 회원정보를 수정하는 함수를 @Transaction구현
단일 회원정보를 수정하는 함수를 @Transaction 구현 → 전파 속성을 propagation = Propagation.REQUIR.REQUIRES_NEW
단일 회원정보 함수를 빠져나와 → 일괄 처리에 실패와 성공한 케이스에 대해 저장하는 로직 구현
@Slf4j @Service @RequiredArgsConstructor public class MemberService{ private final MemberRepository memberRepository; private final MemberHistoryRepository memberHistoryRepository; @Transactional public saveMembers(List<Member> members) { for (Member member : members) { this.saveMember(member); } memberHistoryRepository.save(members); } @Transactional(propagation = Propagation.REQUIRES_NEW) public saveMember(Member member) { memberRepository.save(member); } }
Java
복사
문제 발생
회원 하나가 exception이 발생하면 트랜잭션이 전부 롤백되는 현상이 발생합니다.
문제 원인
하나의 Bean에서 @Transaction 함수를 호출하면 프록시 함수로 인식하지 못하게 되고 결국 일반 함수로 호출되는 것처럼 동작합니다. 이 때문에 일괄 롤백이 진행됩니다.
문제 해결방법
서비스를 분리하여 호출하면 제대로 트랜잭션이 동작합니다. 하지만 궁금한 점은 서비스에서 서비스를 호출하게 되면 복잡도가 올라가게 되므로 질문을 하였습니다.
답변 내용
서비스에서 서비스를 호출하는 구조는 피하고 도메인 레이어에 도메인 서비스를 둬서 처리하는 것을 최범균님이 쓴 '도메인 주도 개발 시작하기(DDD Start)'에서 본 적이 있습니다.
그리고 여러 건 처리를 할 때와 단건 처리를 할 때 트랜잭션을 명시적으로 처리하면 부분 실패와 성공에 대해 읽고 수정하기가 더 좋을 것 같습니다.
도메인 주도 개발 시작하기에 대해 읽어보고 후기를 작성하도록 하겠습니다.

결론

같은 서비스 레이어에서 @Transaction → @Transaction 함수를 호출하면 일반 함수와 같이 작동한다는 것을 알 수 있었고, 이를 방지하기 위해서는 서비스 레이어를 분리해야 합니다. 그러나 복잡도가 올라가기 때문에 이를 해결하기 위해 도메인 주도 개발에 대해 알아보고 정리하도록 하겠습니다.

프록시 관련 설명