TRANSACTION BOUNDARY

서비스 메서드가 한 유스케이스의 커밋 경계를 잡는다

컨트롤러는 요청을 해석하고, 서비스는 함께 성공해야 하는 DB 변경을 하나로 묶고, 외부 부작용은 커밋 밖으로 밀어냅니다.
판단 기준 같이 성공해야 하면 안쪽, 다시 시도해도 되면 바깥쪽 트랜잭션 안에는 DB 일관성을 만드는 작업만 두고, 알림과 결제 연동은 outbox나 after commit으로 분리합니다.
Controller 요청 경계 DTO 검증, 인증 사용자 확인, command 객체 생성 DB 커넥션을 오래 붙잡지 않도록 빠르게 서비스로 넘김
Service.createOrder() 트랜잭션 내부 @Transactional
begin 재고 확인과 차감 읽은 재고와 차감이 같은 커넥션 문맥에서 이어짐
write 주문 저장 orders 행이 생성되고 이후 상세가 같은 주문을 참조
write 주문 항목 저장 order_items가 주문과 상품을 연결하며 금액 스냅샷을 보존
commit 성공 또는 rollback 중간 예외가 전파되면 모든 변경을 취소
After commit 외부 부작용 메일, 알림, 이벤트 발행, 검색 인덱싱
Outbox 실패 재시도 커밋된 이벤트를 별도 작업자가 재전송
원자성 재고 차감과 주문 생성이 분리 커밋되면 안 됩니다.
예외 전파 실패를 삼키면 롤백 규칙이 실행되지 않습니다.
잠금 시간 외부 API를 안쪽에 두면 DB 잠금이 불필요하게 길어집니다.
관찰 가능성 트랜잭션 id와 outbox id를 로그로 연결합니다.
핵심 감각 서비스 레이어 트랜잭션은 “계층이 예뻐 보이게 만드는 장식”이 아니라, 한 유스케이스의 불변식을 어디서 한 번에 보장할지 정하는 경계입니다.