Transaction이란?
데이터베이스의 상태를 변환시키는 하나의 논리적 기능을 수행하기 위한 작업의 단위
Transaction의 특징 + 관련 기능
✅ 원자성 Atomicity + Commit & Rollback
1개의 트랜잭션 내의 연산이 모두 반영되거나 또는 전혀 반영되지 않아야 한다.
- 초기 상태를 임시 영역 Rollback Segment에 저장한다.
- 트랜잭션 내에서 오류 발생 시,
임시 영역에 저장한 상태로 Rollback - 트랜잭션 내 연산 성공 시, Commit
✅ 일관성 Consistency
트랜잭션 처리 결과는 항상 일관적이어야 한다.
✅ 격리성 Isolation + Lock
어떤 트랜잭션이 다른 트랜잭션의 연산에 끼어들 수 없다.
Race Condition(동시에 같은 데이터를 수정하려 할 때 발생하는 경쟁 상태)과 깊게 연관되어 있는 특성이다.
트랜잭션 1이 데이터를 읽거나 쓰기 작업 중일 때, 다른 트랜잭션이 접근하지 못하도록 Lock을 걸어
격리성을 지키고 Race Condition을 방지하는 것이다.
✅ 지속성 Durability
성공적으로 완료된 트랜잭션의 결과는 영구적으로 반영되어야 한다.
Spring에서의 롤백
위의 표와 같이 스프링에서 롤백은 발생한 예외가 런타임 도중에 발생한 예외인가 아닌가에 따라 다르게 처리된다.
- Unchecked Exception (RuntimeException 또는 Error 계열)
Rollback ⭕
try-catch로 처리하여도 catch 여부와 무관하게 Rollback 한다. - Checked Exception
Rollback ❌
@Transactional rollbackFor에 명시적으로 설정해야 롤백된다.
트랜잭션을 관리하는 곳이 내부인지 외부인지에 따라서도 다르게 처리된다.
- 외부에서 관리 (Propagation.REQUIRED)
내부 트랜잭션에서 롤백 마킹이 되어도 외부의 최종 상태에 의존한다. - 내부에서 새로 생긴 트랜잭션인 경우 (Propagation.REQUIRES_NEW)
내부 트랜잭션의 롤백은 외부에 영향을 주지 않는다.
https://techblog.woowahan.com/2606/
응? 이게 왜 롤백되는거지? | 우아한형제들 기술블로그
이 글은 얼마 전 에러로그 하나에 대한 호기심과 의문으로 시작해서 스프링의 트랜잭션 내에서 예외가 어떻게 처리되는지를 이해하기 위해 삽질을 해본 경험을 토대로 쓰여졌습니다. 스프링의
techblog.woowahan.com
Spring이 제공하는 Transaction
- 동기화
- 추상화
- AOP 기반 분리
https://mangkyu.tistory.com/154
[Spring] 트랜잭션에 대한 이해와 Spring이 제공하는 Transaction(트랜잭션) 핵심 기술 - (1/3)
1. Transaction(트랜잭션)에 대한 이해 [ 트랜잭션(Transaction)의 필요성 ] 만약 데이터베이스의 데이터를 수정하는 도중에 예외가 발생된다면 어떻게 해야 할까? DB의 데이터들은 수정이 되기 전의 상
mangkyu.tistory.com
☑️ 트랜잭션 동기화
개발자가 직접 여러 개의 작업을 하나의 트랜잭션으로 관리하려면 Connection 객체를 공유하는 등의 작업이 필요하다.
Spring은 Connection 객체를 특별한 저장소에 보관해 두고 필요할 때 꺼내쓸 수 있도록 하는 기술을 제공한다.
- 스레드마다 독립적으로 동기화 저장소의 Connection 객체를 관리한다.
☑️ 트랜잭션 추상화
Spring은 JDBC 종속적인 트랜잭션 동기화 코드들로 인해 유발되는 문제를 해결하기 위해 트랜잭션 관리 부분을 추상화하였다.
종속적이다.
= JDBC는 Connection 기반 트랜잭션이지만 JPA는 EntityManager, Hibernate는 Session 기반
= 사용하는 리소스가 다름
PlatformTransactionManager를 통해 사용하는 기술과 무관하게 트랜잭션을 일관적으로 관리할 수 있다!
☑️ AOP 기반 분리
트랜잭션 관리 코드들이 비즈니스 로직 코드와 결합되어 2가지 이상의 책임을 가지게 되는 경우 이를 어떻게 분리할 수 있을까?
바로 AOP를 이용하는 것이다!
- 트랜잭션 코드 같은 부가 기능 코드가 존재하지 않는 것처럼 보이게 한다.
- 클래스에서 분리하여 별도의 모듈로 만든다.
트랜잭션 처리 과정
- Controller
클라이언트의 요청에 따라 Controller가 호출되면 처리에 필요한 서비스를 호출함 - TransactionInterceptor 동작
@Transactional 명시된 경우
Spring AOP가 TransactionInterceptor로 메서드 호출을 가로챔
TransactionAttributeSource로 트랜잭션 속성 파악 - TransactionAttribute 추출 & 해석
TransactionAttributeSource 구현체인 AnnotationTransactionAttributeSource는 리플렉션을 사용하여 메서드의 @Transactional을 찾아 분석
분석 결과를 TransactionAnnotationParser 구현체인 SpringTransactionAnnotationParser TransactionAttribute로 변환 - 트랜잭션 시작 또는 참여 결정
TransactionInterceptor는 현재 진행 중인 트랜잭션이 있으면 해당 트랜잭션에 참여하거나, 없으면 새로운 트랜잭션을 시작 - 서비스 메서드 실행
- 트랜잭션 커밋 또는 롤백
Spring 트랜잭션 세부 설정
💡트랜잭션 전파
어떤 트랜잭션이 동작 중인 과정에서 다른 트랜잭션을 실행할 경우 어떻게 처리하는 가
https://sjh9708.tistory.com/243
[Spring Boot] 트랜잭션 범위와 전파 속성(Propagation)
트랜잭션은 작업에서 예외가 발생할 경우 Rollback 처리를, 모두 성공할 경우 Commit 처리하는 실행 단위이다.Spring에서는 트랜잭션과 관련된 기술들을 제공하며, 주로 @Transactional 어노테이
sjh9708.tistory.com
Propagation.REQUIRED (기본값)
기존 트랜잭션이 있으면 사용하고 없으면 새로 만든다.
- 대부분의 비즈니스 로직
Propagation.REQUIRES_NEW
항상 새로운 트랜잭션이 필요하다.
- 독립적인 작업 처리
Propagation.NESTED
중첩 트랜잭션을 생성한다.
- 하위 메서드에서 예외 발생 시, 중첩된 트랜잭션만 롤백
- 임시 저장같이 부분적으로 롤백이 가능한 작업
Propagation.MANDATORY
트랜잭션이 의무이다.
- 기존 트랜잭션이 없다면 IllegalTransactionStateException 발생
- 트랜잭션 내부에서만 호출 가능한 메서드에서 사용
Propagation.SUPPORTS
기존 트랜잭션이 있으면 사용하고 없으면 새로 만들지는 않고 없이 진행한다.
- 트랜잭션이 없는 상태에서 하위 메서드에서 예외가 발생 시, 트랜잭션과 관계없이 예외 처리
- 트랜잭션이 필수가 아닌 작업
Propagation.NOT_SUPPORTED
트랜잭션 미지원, 기존에 트랜잭션이 있어도 이를 중지하고 없는 상태로 실행한다.
- 로그 저장 등 트랜잭션과 독립적인 작업
Propagation.NEVER
트랜잭션 미지원, 상위 스코프에도 트랜잭션이 설정돼 있으면 안 된다.
- 트랜잭션 설정 시, IllegalTransactionStateException 발생
- 외부 시스템 호출 작업
❗@Transaction 전파 주의사항
한 서비스의 메서드에서 두 개 이상의 트랜잭션을 생성하지 않도록 하라!
@Transactianal은 프록시 기반으로 동작하기 때문에 외부에서 접근할 때 AOP를 통해서 프록시 객체를 접근할 수 있다.
@Transactional
public Long A() {
return B();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public Long B() {
return ...;
}
위의 코드와 같이 A 메서드 내에서 REQUIRES_NEW가 선언된 B 메서드를 호출할 때,
별도의 트랜잭션이 생성되어 B가 실행될까?
아니다!
클래스내에서 다른 메서드를 호출하게 되면 프록시로 접근하지 않고 직접 접근하기 때문에
메서드에 선언해 놓은 @Transactinal이 정상적으로 동작하지 않는다.
별도의 트랜잭션을 사용하고자 한다면
별도의 서비스를 만들어주어야 한다!
https://velog.io/@myspy/Transaction-%EC%A0%84%ED%8C%8C%EA%B0%80-%EB%AD%A1%EB%8B%88%EA%B9%8C
Transaction 전파가 뭡니까?
이전 포스팅에서 Transactional을 학습한 이후에 Transactional 전파에 대한 학습을 약속했기 때문에 Transactional 전파라는 주제로 추가학습을 진행하게 됐다. 어떤 트갠잭션이 동작중인 과정에서 다른
velog.io
💡격리 수준 (DB마다 다름 주의)
서버에서는 여러 개의 트랜잭션이 동시에 진행될 수 있다.
그러나, 모든 트랜잭션을 독립적이고 순차적으로 진행한다면 안정적이지만 성능이 크게 떨어진다.
따라서 적절하게 격리수준을 조정해서 가능한 많은 트랜잭션을 동시에 진행시키면서 문제가 발생하지 않도록 제어해야 한다.
= 일관성이 깨지는 것을 어느 정도까지 허용하는가
Dirty Read : 다른 트랜잭션에 의해 수정되었지만, 아직 커밋되지 않은 상태의 데이터를 읽는 것
Non-Repeatable Read : 하나의 트랜잭션에서 같은 키를 가진 데이터를 두 번 읽을 때, 그 결과가 다르게 나타나는 현상
Phantom Read : 일정 범위의 데이터를 여러번 읽을 때, 처음에는 없던 유령(Phantom) 데이터가 이후에는 나타나는 현상
READ UNCOMMITTED = 열린문
아직 커밋되지 않은 데이터도 다른 트랜잭션에서 접근 가능
Dirty Read 발생 가능!
Non-Repeatable Read 가능!
Phantom Read 가능!
READ COMMITTED
커밋된 데이터만 다른 트랜잭션에서 읽기 가능
Non-Repeatable Read 가능!
Phantom Read 가능!
REPEATABLE READ
트랜잭션 내에서 같은 조건으로 같은 레코드를 여러 번 조회했을 때 항상 같은 결과를 보장
데이터 변경 전의 레코드를 UNDO 공간에 백업,
그 사이에 다른 트랜잭션이 커밋되었더라도 UNDO 공간에 백업해놓은 데이터를 참조해 항상 같은 조회 결과를 보장
Phantom Read 가능!
SERIALIZABLE = 넌 못 지나간다.
데이터 접근 시 락을 걸어서 같은 데이터에 다른 트랜잭션이 동시에 접근할 수 없는 격리 수준
가장 안전하지만 가장 성능이 떨어짐
읽기 전용 readOnly
- 쓰기 지연(Dirty Checking) 기능 비활성화, flush 시점에 INSERT, UPDATE, DELETE SQL 생성 금지로 인한 최적화
- 쓰기 작업 발생을 의도적으로 방지
읽기 전용 트랜잭션이 시작된 이후 INSERT, UPDATE, DELETE의 작업이 진행되면 예외가 발생한다.
그래서 일단 서비스 클래스 상단에 @Transaction(readOnly = true)를 명시한 후,
쓰기 작업이 필요한 메서드의 경우에만 @Transaction을 써주는 습관도 좋다.
@Service
@Transactional(readOnly = true) // 기본적으로 모든 메서드는 읽기 전용
public class MemberService {
// 쓰기 메서드 → 트랜잭션 재정의
@Transactional
public Long registerMember(Member member) {
memberRepository.save(member);
return member.getId();
}
}
'개발 지식' 카테고리의 다른 글
TSM (Transaction Synchronization Manager) (1) | 2025.08.17 |
---|---|
디자인 패턴에서 발견하는 객체지향 (0) | 2025.08.06 |
실무에서 사용하는 Java와 Spring 버전 (0) | 2025.08.06 |
한 호흡으로 정리하는 객체지향 (0) | 2025.08.05 |
Git 커밋 컨벤션을 지키면서 Commit하기! (0) | 2025.03.07 |