[Spring] Transaction Propagation

phdljr·2025년 4월 2일

서론

트랜잭션 전파(Propagation)는 메서드가 기존 트랜잭션을 유지할지, 새로운 트랜잭션을 생성할지, 아니면 트랜잭션 없이 실행할지를 결정하는 정책

@Transactional(propagation = Propagation.REQUIRED)

스프링 트랜잭션 전파 종류

  • REQUIRED (기본값): 기존 트랜잭션이 있으면 참여, 없으면 새 트랜잭션 생성
  • REQUIRES_NEW: 기존 트랜잭션을 무시하고 항상 새로운 트랜잭션 생성
  • SUPPORTS: 트랜잭션이 있으면 참여, 없으면 트랜잭션 없이 실행
  • NOT_SUPPORTED: 트랜잭션을 사용하지 않고 실행
  • MANDATORY: 기존 트랜잭션이 있어야 실행 (없으면 예외 발생)
  • NEVER: 트랜잭션 없이 실행 (기존 트랜잭션이 있으면 예외 발생)
  • NESTED: 기존 트랜잭션이 있으면 중첩 트랜잭션 사용 (저장점 SAVEPOINT 생성)

REQUIRED (기본값)

  • 기존 트랜잭션이 있으면 그 트랜잭션을 사용
  • 없으면 새로운 트랜잭션 생성
  • 부모 메서드에서 예외가 발생하면 자식 트랜잭션도 롤백
@Service
public class ParentService {
    @Autowired
    private ChildService childService;

    @Transactional(propagation = Propagation.REQUIRED)
    public void parentMethod() {
        saveParentData();
        childService.childMethod(); // 같은 트랜잭션에 포함됨
    }
}

@Service
public class ChildService {
    @Transactional(propagation = Propagation.REQUIRED) // 기본값
    public void childMethod() {
        saveChildData(); // parentMethod와 같은 트랜잭션
    }
}

REQUIRES_NEW

  • 항상 새로운 트랜잭션을 생성
  • 부모 트랜잭션과 독립적으로 실행됨
  • 부모 트랜잭션이 롤백되어도 자식 트랜잭션은 롤백되지 않음
  • 부모 트랜잭션과 별개로 실행되기 때문에 부모가 롤백되어도 자식 데이터는 유지됨
@Service
public class ParentService {
    @Autowired
    private ChildService childService;

    @Transactional
    public void parentMethod() {
        saveParentData();
        try {
            childService.childMethod(); // 별도 트랜잭션
        } catch (Exception e) {
            // 예외 처리
        }
    }
}

@Service
public class ChildService {
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void childMethod() {
        saveChildData();
        throw new RuntimeException("예외 발생!"); // 여기서 예외가 발생해도 부모 트랜잭션 영향 X
    }
}

NESTED

  • 기존 트랜잭션이 있으면 중첩 트랜잭션을 생성 (SAVEPOINT 활용)
  • 부모 트랜잭션이 롤백되면 자식도 롤백됨
  • 자식 트랜잭션만 롤백 가능 (부모 트랜잭션 유지)
  • 부모 트랜잭션이 커밋되면 자식도 커밋되지만, 자식 트랜잭션만 롤백할 수도 있음
@Service
public class ParentService {
    @Autowired
    private ChildService childService;

    @Transactional
    public void parentMethod() {
        saveParentData();
        try {
            childService.childMethod();
        } catch (Exception e) {
            // 자식 트랜잭션만 롤백됨
        }
    }
}

@Service
public class ChildService {
    @Transactional(propagation = Propagation.NESTED)
    public void childMethod() {
        saveChildData();
        throw new RuntimeException("예외 발생!"); // SAVEPOINT까지 롤백
    }
}

MANDATORY

  • 부모 트랜잭션이 반드시 존재해야 함
  • 트랜잭션이 없으면 IllegalTransactionStateException 발생
@Service
public class SomeService {
	// 해당 메서드는 반드시 부모 트랜잭션이 존재한 상태로 호출돼야 함
    @Transactional(propagation = Propagation.MANDATORY)
    public void someMethod() {
        saveData();
    }
}

NEVER

  • 트랜잭션 없이 실행
  • 기존 트랜잭션이 있으면 예외 발생
@Service
public class SomeService {
	// 해당 메서드는 반드시 부모 트랜잭션이 없는 상태로 호출돼야 함
    @Transactional(propagation = Propagation.NEVER)
    public void someMethod() {
        saveData();
    }
}
profile
난 Java도 좋고, 다른 것들도 좋아

0개의 댓글