Search
moon
sun

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

프록시 관련 설명