1. isolation — 트랜잭션 격리 수준
트랜잭션 간의 읽기/쓰기 충돌을 어떻게 막을지 설정합니다.
@Transactional(isolation = Isolation.REPEATABLE_READ
| 값 | 설명 | 방지되는 문제 |
| READ_UNCOMMITTED | 커밋 안 된 데이터도 읽기 허용 | 없음 (가장 낮은 수준) |
| READ_COMMITTED | 커밋된 데이터만 읽음 (기본) | Dirty Read 방지 |
| REPEATABLE_READ | 트랜잭션 동안 같은 행은 같은 값으로 보장 | Non-repeatable Read 방지 |
| SERIALIZABLE | 가장 엄격한 수준, 전체 정렬된 트랜잭션처럼 동작 | Phantom Read까지 방지 |
💡 기본값은 DBMS에 따라 다르지만 대부분 READ_COMMITTED
2. propagation — 트랜잭션 전파 방식
이미 진행 중인 트랜잭션이 있다면 이 메서드는 어떻게 실행되어야 할까?
@Transactional(propagation = Propagation.REQUIRED)
| 값 | 설명 |
| REQUIRED | 기존 트랜잭션이 있으면 참여, 없으면 새로 시작 (기본값) |
| REQUIRES_NEW | 무조건 새 트랜잭션 시작 (기존 것은 일시 중단) |
| NESTED | 부모 트랜잭션 안에 중첩 트랜잭션 시작 (rollback 분리 가능) |
| SUPPORTS | 트랜잭션 있으면 참여, 없으면 그냥 실행 |
| MANDATORY | 반드시 트랜잭션 있어야 함, 없으면 예외 |
| NEVER | 트랜잭션 있으면 예외 발생 |
| NOT_SUPPORTED | 트랜잭션 없이 실행 (기존 트랜잭션 중단) |
🧠 트랜잭션 분리/중첩이 필요한 경우 반드시 설정 고려
3. readOnly — 읽기 전용 최적화
@Transactional(readOnly = true)
- 쓰기 연산이 없는 메서드에 설정하면 성능 최적화
- JPA에서는 **더티 체킹(변경 감지)**이 비활성화되어 flush 생략 가능
⚠️ 주의:
- readOnly = true인데 save() 등 쓰기 시도하면 예외는 나지 않지만 의도와 어긋납니다
4. rollbackFor — 트랜잭션 롤백 예외 지정
Spring은 기본적으로 RuntimeException과 Error만 롤백 대상입니다.
하지만 체크 예외(Exception)가 발생하면 롤백이 되지 않아요.
@Transactional(rollbackFor = IOException.class)
- 이 설정을 통해 체크 예외로도 롤백이 가능하게 만듭니다
✅ 반대 설정도 있음: noRollbackFor
5. timeout — 트랜잭션 최대 실행 시간 (초 단위)
@Transactional(timeout = 10) // 10초 안에 끝나야 함
- 트랜잭션이 설정한 시간 안에 끝나지 않으면 롤백 발생
- DB 락 대기 방지, 무한 대기 방지용으로 사용
⚠️ JPA 사용 시에는 실제 DB에 따라 제대로 적용되지 않는 경우도 있음 → DB 설정 병행 필요
✨ 종합
@Transactional(
isolation = Isolation.REPEATABLE_READ,
propagation = Propagation.REQUIRES_NEW,
readOnly = false,
rollbackFor = {SQLException.class},
timeout = 5
)
public void updateAccount() {
// 5초 안에 끝나야 하고,
// 별도 트랜잭션으로 실행되며,
// SQLException 발생 시 롤백됩니다.
}
✅ 요약표
| 속성 | 역할 |
| isolation | 트랜잭션 간 읽기 격리 수준 설정 |
| propagation | 트랜잭션 전파 방식 제어 |
| readOnly | 읽기 전용 최적화 (쓰기 방지) |
| rollbackFor | 어떤 예외에서 롤백할지 지정 |
| timeout | 트랜잭션 최대 실행 시간 제한 (초 단위) |