@Transactional 어노테이션 적용 전략

임동혁 Ldhbenecia·2025년 6월 27일

SpringBoot

목록 보기
19/28
post-thumbnail

대부분의 개발자들은 insert, update, delete 쿼리가 발생하는 메서드에 습관적으로 @Transactional을 적용한다.

일반적인 @Transactional 사용 패턴

@Transactional
fun append(data: String) {
    abcProcessor.append(data + "1")
}

이런 단순한 경우에는 문제가 없다. 하지만 외부 서비스 호출이 포함된 경우에는 상황이 달라진다.

@Transactional 남발의 문제점

외부 서비스 호출로 인한 리소스 낭비

@Transactional
fun append(data: String) {
    smsSender.send(~~)
    abcProcessor.append(data + "1")

    slackNotifier.notify(~~)
}

이 코드의 문제점:

  • SMS 발송과 Slack 알림은 데이터베이스 작업이 아님에도 트랜잭션 내에서 실행됨
  • 외부 서비스 타임아웃(예: 30초)동안 트랜잭션이 유지됨
  • 외부 서비스 장애 시 데이터베이스 커넥션 풀 고갈 가능성

리소스 점유 시나리오

외부 SMS 서비스에 장애가 발생하여 30초 타임아웃이 발생한다고 가정하자:

  1. 해당 메서드가 초당 100회 호출됨
  2. 각 호출마다 30초간 트랜잭션 유지
  3. 최악의 경우 3000개의 트랜잭션이 동시에 활성화
  4. 데이터베이스 커넥션 풀 고갈로 인한 시스템 장애

개선 방안

1. 트랜잭션 범위 최소화

fun append(data: String) {
    smsSender.send(~~)
    abcProcessor.append(data + "1")// 이 메서드 내부에서만 @Transactional 적용

    slackNotifier.notify(~~)
}

Implementation Layer의 구현부에서만 트랜잭션을 적용한다:

class AbcProcessorImpl {
    @Transactional
    fun append(data: String) {
// 실제 데이터베이스 작업만 트랜잭션 내에서 수행
    }
}

2. 복합 트랜잭션이 필요한 경우

여러 프로세서의 작업이 하나의 트랜잭션으로 묶여야 하는 경우:

fun append(data: String) {
    smsSender.send(~~)
    abcProcessor.append(data + "1")// @Transactional 적용됨
    bcaProcessor.appendNoTran(data + "2")// @Transactional 적용됨

    slackNotifier.notify(~~)
}

이 두 프로세서의 작업이 반드시 같은 트랜잭션에서 실행되어야 한다면, Implementation Layer에서 하나의 구현체로 통합한다

class CombinedProcessorImpl {
    @Transactional
    fun appendBoth(data: String) {
// abcProcessor와 bcaProcessor의 로직을 하나의 트랜잭션에서 실행
// 결합도가 높다는 것을 인정하고 명시적으로 처리
    }
}

트랜잭션 적용 원칙

1. 필요한 곳에만 적용

  • 실제 데이터베이스 작업이 있는 메서드에만 적용
  • 외부 서비스 호출은 트랜잭션 범위에서 제외

2. 트랜잭션 범위 최소화

  • 가능한 한 가장 하위 레이어(Implementation Layer)에서 적용
  • 비즈니스 로직과 데이터베이스 작업을 분리

3. 명시적 트랜잭션 관리

  • 여러 작업이 하나의 트랜잭션으로 묶여야 하는 경우 명시적으로 처리
  • 결합도가 높아지는 것을 인정하고 적절한 설계로 대응

성능 최적화 효과

Before (트랜잭션 남발)

SMS 발송 (30초) + DB 작업 (0.1초) + Slack 알림 (5초) = 35.1초 트랜잭션 유지

After (트랜잭션 최적화)

SMS 발송 (30초, 트랜잭션 없음) + DB 작업 (0.1초, 트랜잭션) + Slack 알림 (5초, 트랜잭션 없음)
실제 트랜잭션 시간: 0.1초

트랜잭션 유지 시간이 350배 단축되어 시스템 전체의 처리량이 대폭 향상된다.

결론

@Transactional 어노테이션은 강력한 도구지만 신중하게 사용해야 한다. 무분별한 적용은 시스템 성능을 크게 저하시킬 수 있다.
실제 데이터베이스 작업이 필요한 최소한의 범위에만 적용하고, 외부 서비스 호출과는 분리하여 설계하는 것이 중요하다. 복합 트랜잭션이 필요한 경우에는 결합도 증가를 감수하더라도 명시적으로 처리하는 것이 바람직하다.

학습 출처

https://www.youtube.com/watch?v=mB3g3l-EQp0

0개의 댓글