[Spring Boot] 트랜잭션(Transaction) 가이드

KUKJIN LEE's profile picture

KUKJIN LEE1주 전 작성

Spring Boot에서 트랜잭션(Transaction)은 데이터의 일관성을 보장하고, 여러 작업을 하나의 논리적 단위로 묶어 처리할 수 있도록 지원합니다.

 

트랜잭션(Transaction)이란?

트랜잭션은 데이터베이스에서 일련의 작업 단위를 말하며, 작업이 모두 성공하거나, 실패 시 전부 롤백(rollback)되어야 하는 원자성을 보장합니다. 따라서 Spring Boot만을 위한 내용이 아니라, CS 지식으로 반드시 알고가야 하는 내용 중 일부입니다.

 

트랜잭션의 ACID 속성

  1. Atomicity (원자성): 모든 작업이 성공하거나 실패 시 모두 취소됩니다.

  2. Consistency (일관성): 작업 완료 후 데이터베이스 상태가 일관성을 유지합니다.

  3. Isolation (격리성): 동시에 실행되는 트랜잭션이 서로에게 영향을 미치지 않습니다.

  4. Durability (지속성): 트랜잭션이 완료되면 데이터는 영구적으로 저장됩니다.

 

Spring Boot에서 트랜잭션 설정

Spring Boot는 트랜잭션 관리를 간소화하며, @Transactional 어노테이션을 통해 쉽게 구현할 수 있습니다.

 

의존성 추가

Spring Boot에서 트랜잭션을 사용하려면 기본적으로 JPA나 JDBC 의존성이 필요합니다.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

 

@EnableTransactionManagement 활성화

Spring Boot는 기본적으로 트랜잭션 관리를 활성화하지만, @EnableTransactionManagement설정을 통해 커스터마이징 가능합니다.

import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@EnableTransactionManagement
public class TransactionConfig {
    // 커스텀 트랜잭션 설정 (필요 시)
}

 

@Transactional 사용법

Spring Boot에서 트랜잭션 처리를 위해 주로 사용하는 어노테이션입니다.

기본 사용

트랜잭션을 적용하려는 메서드나 클래스에 @Transactional을 추가합니다.

클래스에 적용

클래스 전체의 메서드에 트랜잭션을 적용합니다.

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional
public class UserService {
    public void createUser(User user) {
        // 모든 작업이 하나의 트랜잭션 내에서 처리됨
    }
}

메서드에 적용

특정 메서드에만 트랜잭션을 적용합니다.

import org.springframework.transaction.annotation.Transactional;
@Transactional
public void updateUser(User user) {
    // 트랜잭션 처리 로직
}

 

트랜잭션 속성

기본 설정으로 충분합니다. 특별한 이유가 없다면 기본 `@Transactional` 어노테이션으로 충분합니다. 이펙티브 수준을 원하시는 게 아니라면 그냥 읽고 넘어가도 좋습니다.

주요 속성

  • propagation: 트랜잭션 전파 방식.

  • isolation: 트랜잭션 격리 수준.

  • timeout: 트랜잭션 제한 시간.

  • readOnly: 읽기 전용 여부.

@Transactional(
    propagation = Propagation.REQUIRED,
    isolation = Isolation.READ_COMMITTED,
    timeout = 5,
    readOnly = false
)
public void processTransaction() {
    // 트랜잭션 내 처리
}

 

전파(Propagation) 옵션

트랜잭션의 전파 방식을 설정하여 기존 트랜잭션과의 관계를 정의합니다.

옵션

설명

REQUIRED

기본 값. 기존 트랜잭션이 있으면 참여, 없으면 새로 시작.

REQUIRES_NEW

항상 새로운 트랜잭션을 시작. 기존 트랜잭션은 보류.

NESTED

기존 트랜잭션 내에서 중첩 트랜잭션을 시작.

SUPPORTS

기존 트랜잭션이 있으면 참여, 없으면 트랜잭션 없이 실행.

NOT_SUPPORTED

트랜잭션 없이 실행. 기존 트랜잭션은 보류.

MANDATORY

반드시 기존 트랜잭션에 참여. 없으면 예외 발생.

NEVER

트랜잭션 없이 실행. 기존 트랜잭션이 있으면 예외 발생.

 

격리 수준(Isolation Level)

트랜잭션 간 간섭을 방지하기 위한 격리 수준을 설정합니다.

옵션

설명

DEFAULT

데이터베이스 기본 격리 수준 사용.

READ_UNCOMMITTED

다른 트랜잭션의 미완료 변경 내용 읽기 허용.

READ_COMMITTED

커밋된 데이터만 읽기 허용. (기본)

REPEATABLE_READ

트랜잭션 동안 동일한 데이터 읽기 보장.

SERIALIZABLE

가장 높은 격리 수준. 트랜잭션 순차 실행.

 

실무에서의 트랜잭션 활용

트랜잭션 롤백

Spring Boot에서 예외 발생 시 트랜잭션은 자동으로 롤백됩니다.

  • 기본적으로 RuntimeExceptionError는 롤백됩니다.

  • CheckedException은 기본적으로 롤백되지 않으므로, 명시적으로 설정해야 합니다.

@Transactional(rollbackFor = Exception.class)
public void processTransaction() throws Exception {
    // 작업 수행 중 예외 발생 시 롤백
    throw new Exception("Rollback Test");
}

읽기 전용 트랜잭션

읽기 전용 작업에는 readOnly = true를 설정하여 성능을 최적화할 수 있습니다.

@Transactional(readOnly = true)
public List<User> getUsers() {
    return userRepository.findAll();
}

트랜잭션 관리 주의사항

  1. @Transactional은 public 메서드에서만 동작

    • Spring AOP 기반으로 동작하므로, private 메서드에서는 트랜잭션이 적용되지 않습니다.

  2. 자기 호출(self-invocation) 문제

    • 같은 클래스 내에서 @Transactional이 선언된 메서드를 호출하면 트랜잭션이 적용되지 않을 수 있습니다.

  3. 읽기 전용 설정

    • 읽기 전용 작업에서 쓰기 작업을 수행하면 예외가 발생할 수 있습니다.

  4. DB 락(lock) 주의

    • 높은 격리 수준(예: SERIALIZABLE)은 데드락 가능성을 높일 수 있으므로 주의해야 합니다.

New Tech Posts