반응형
Notice
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
Tags
- 프로그래밍언어
- 사이버보안
- 데이터과학
- 데이터구조
- Yes
- 자바스크립트
- 딥러닝
- 빅데이터
- 파이썬
- 머신러닝
- 소프트웨어
- I'm Sorry
- 컴퓨터비전
- 프로그래밍
- 자료구조
- 인공지능
- 데이터분석
- springboot
- 디자인패턴
- 웹개발
- 컴퓨터공학
- 컴퓨터과학
- 소프트웨어공학
- 버전관리
- 보안
- 네트워크보안
- 클라우드컴퓨팅
- 알고리즘
- 데이터베이스
- 네트워크
Archives
- Today
- Total
스택큐힙리스트
트랜잭션 전파·격리 수준 완전 정복 본문
반응형
1️⃣ 트랜잭션 전파(Propagation)란?
스프링 AOP 프록시가 현재 실행 중인 트랜잭션을 “새로 만들지, 이어받지, 잠깐 끊을지” 결정하는 규칙입니다.
전파 옵션 | 의미 (한 줄 요약) |
REQUIRED (기본) | ❝있으면 참여, 없으면 새로 생성❞ – 80 % 이상 이걸로 OK |
REQUIRES_NEW | ❝무조건 새 트랜잭션❞ – 외부 트랜잭션과 독립 커밋/롤백 |
NESTED | ❝논리적 내부 트랜잭션❞ – Savepoint 기반 부분 롤백 가능 |
SUPPORTS / NOT_SUPPORTED | ❝있으면 따라가고 / 완전히 비트랜잭션❞ |
MANDATORY / NEVER | ❝반드시 있어야 함 / 있으면 안 됨❞ – Assertion 용 |
실전 팁
- REQUIRES_NEW는 알림 메일·로그 저장처럼 메인 로직 실패와 분리하고 싶을 때.
- NESTED는 배치 처리 중 일부 레코드만 롤백할 때 유용.
- 트랜잭션 경계는 Service 계층에만! Controller나 Repository에 붙이지 말 것.
2️⃣ 트랜잭션 격리 수준(Isolation Level)은 왜 필요할까?
동시에 실행되는 트랜잭션 간 “더티 리드·반복 불가·팬텀 리드” 같은 이상 현상을 얼마나 막을지 정하는 레버입니다.
- READ_UNCOMMITTED : 다른 트랜잭션의 미커밋 데이터를 읽음 → 거의 쓰지 않음
- READ_COMMITTED : 커밋된 데이터만 읽음 (MySQL InnoDB 기본)
- REPEATABLE_READ : 같은 트랜잭션 내에서 같은 결과 보장, 팬텀 리드는 허용
- SERIALIZABLE : 가장 엄격, 사실상 순차 실행 — 성능 부담 大
- DEFAULT : DB 벤더 기본값을 그대로 사용
성능 ↔ 일관성 트레이드오프
👉 OLTP 서비스는 대부분 READ_COMMITTED / REPEATABLE_READ가 안정적.
👉 대량 정산 배치나 회계 처리에는 SERIALIZABLE 고려.
3️⃣ 실전 예제: 전파 + 격리 한 방에 세팅
@Service
@RequiredArgsConstructor
public class PaymentService {
private final OrderRepository orderRepository;
private final PayGateway payGateway;
// 주문 결제 로직 – 메인 트랜잭션
@Transactional(isolation = Isolation.REPEATABLE_READ)
public void placeOrder(OrderRequest req) {
Order order = orderRepository.save(req.toEntity());
try {
// 부수 작업은 새 트랜잭션으로 분리
sendPayRequest(order);
} catch (RuntimeException e) {
log.warn("결제 요청 실패, 주문만 롤백");
throw e; // placeOrder 전체 롤백
}
}
// 결제망 호출 – 실패해도 주문 테이블은 영향 없음
@Transactional(propagation = Propagation.REQUIRES_NEW,
isolation = Isolation.READ_COMMITTED)
public void sendPayRequest(Order order) {
payGateway.request(order);
}
}
- placeOrder() 실패 시 두 트랜잭션 모두 롤백.
- sendPayRequest()만 실패하면 주문 트랜잭션에 영향 없고, 재시도 로직 붙이기 용이.
4️⃣ 흔한 실수
- REQUIRES_NEW 남발 → 커넥션 풀 고갈·Deadlock 가능.
- Service A → Service B 호출 시 각자 @Transactional 기본(REQUIRED) 달아 놓고 “중첩” 되는 줄 착각. 실제로는 단일 트랜잭션!
- Isolation 높이기로 동시성 버그 해결하려다 성능 폭락.
5️⃣ 마무리
- 전파 옵션은 ”왜 분리해야 하는가?”를 먼저 묻고 설정
- 격리 수준은 DB 기본값을 믿되, 비즈니스 요구로 올릴 땐 부하 테스트
- 테스트 코드에서 @Transactional(propagation = Propagation.NOT_SUPPORTED) 로 “진짜 커밋” 상태 검증
반응형
'개발' 카테고리의 다른 글
자바 스프링 개발 시작하기 - 12일차 로그인·회원가입·토큰 재발급 플로우 (1) | 2025.07.19 |
---|---|
Kotlin 코루틴에서 트랜잭션 전파 이슈 잡기 (0) | 2025.07.18 |
자바 스프링 개발 시작하기 - 11일차 Spring Data JPA로 데이터 접근 레이어 설계 (0) | 2025.07.18 |
Facade vs Adapter: 언제 퍼사드, 언제 어댑터? (0) | 2025.07.18 |
Facade 패턴 이름의 비밀: ‘건물 외관’에서 온 한 줄 인터페이스 (0) | 2025.07.18 |
Comments