@Transactional

DDEO._.NU·2024년 11월 21일

Spring

목록 보기
1/5
post-thumbnail

@Transactional

📌@Transactional은 스프링 프레임워크에서 제공하는 어노테이션으로, 트랜잭션 관리를 선언적으로 적용할 수 있도록 도와줍니다.
데이터베이스의 상태를 일관되게 유지하고 작업 도중 문제가 발생했을 때 데이터를 롤백하여 안정성을 보장하는데 사용됩니다.

트랜잭션의 기본 개념

트랜잭션은 데이터베이스의 논리적 작업 단위로, 다음 4가지 속성을 가집니다(ACID).

  • Atomicity (원자성): 작업이 모두 성공하거나 모두 실패해야 합니다.
  • Consistency (일관성): 트랜잭션이 완료된 후 데이터는 일관된 상태여야 합니다.
  • Isolation (고립성): 동시에 실행되는 트랜잭션이 서로 영향을 미치지 않아야 합니다.
  • Durability (지속성): 트랜잭션이 성공적으로 완료되면 결과가 영구적으로 저장됩니다.
  • @Transactional은 이러한 트랜잭션의 속성을 코드에서 간단히 관리할 수 있도록 해줍니다.

@Transactional의 작동 원리

스프링은 @Transactional을 적용하기 위해 AOP(Aspect-Oriented Programming)프록시(proxy)를 사용합니다:

  1. 프록시 생성: @Transactional이 선언된 클래스 또는 메서드에 대해 스프링이 프록시 객체를 생성합니다.
  2. 트랜잭션 시작: 프록시 객체가 호출되면 트랜잭션을 시작합니다.
  3. 비즈니스 로직 실행: 실제 메서드를 호출하여 비즈니스 로직을 실행합니다.
  4. 커밋 또는 롤백:
    • 메서드 실행이 성공하면 트랜잭션을 커밋(commit)합니다.
    • 실행 중 예외가 발생하면 트랜잭션을 롤백(rollback)합니다.

@Transactional의 주요 속성

@Transactional에는 다양한 속성을 지정하여 트랜잭션의 동작을 제어할 수 있습니다.

1. propagation (전파 수준)

트랜잭션이 실행되는 방식을 제어합니다. 주요 옵션:

REQUIRED (기본값): 현재 트랜잭션이 있으면 참여하고, 없으면 새로운 트랜잭션을 시작합니다.
REQUIRES_NEW : 항상 새로운 트랜잭션을 시작하며, 기존 트랜잭션은 일시 정지됩니다.
NESTED : 기존 트랜잭션 내부에 중첩된 트랜잭션을 생성합니다.
MANDATORY : 반드시 기존 트랜잭션이 있어야 하며, 없으면 예외가 발생합니다.
SUPPORTS : 트랜잭션이 있으면 참여하고, 없으면 트랜잭션 없이 실행합니다.
NOT_SUPPORTED : 트랜잭션 없이 실행하며, 기존 트랜잭션은 일시 정지됩니다.
NEVER : 트랜잭션이 있으면 예외를 발생시킵니다.

2. isolation (격리 수준)

트랜잭션 간 데이터 접근 방식을 설정합니다. 주요 옵션:

DEFAULT : 데이터베이스의 기본 격리 수준을 따릅니다.
READ_UNCOMMITTED: 다른 트랜잭션에서 커밋되지 않은 데이터를 읽을 수 있습니다.
READ_COMMITTED : 커밋된 데이터만 읽습니다(기본값).
REPEATABLE_READ : 트랜잭션이 진행되는 동안 동일한 데이터를 반복해서 읽어도 항상 같은 값이 보장됩니다.
SERIALIZABLE : 가장 엄격한 수준으로, 트랜잭션 간 완전한 고립을 보장합니다.

3. rollbackFor와 noRollbackFor

rollbackFor : 특정 예외가 발생하면 롤백합니다.

@Transactional(rollbackFor = CustomException.class)

noRollbackFor : 특정 예외가 발생해도 롤백하지 않습니다.

@Transactional(noRollbackFor = CustomException.class)

4. readOnly

true : 데이터 읽기 전용 작업을 지정합니다(최적화).
false (기본값): 읽기/쓰기 작업을 허용합니다.

5. timeout

트랜잭션이 실행될 수 있는 최대 시간을 초 단위로 설정합니다. 기본값은 무제한입니다.

사용 방법

1. 클래스 수준에서 사용

클래스에 @Transactional을 붙이면 모든 메서드에 트랜잭션이 적용됩니다.

@Service
@Transactional
public class MyService {
    public void someMethod() {
        // 트랜잭션이 적용됨
    }
}

2. 메서드 수준에서 사용

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

@Service
public class MyService {
    @Transactional
    public void someMethod() {
        // 트랜잭션이 적용됨
    }

    public void anotherMethod() {
        // 트랜잭션이 적용되지 않음
    }
}

예외 처리 및 롤백

1. 기본 롤백 동작

RuntimeException과 그 하위 클래스가 발생하면 롤백됩니다.
CheckedException은 기본적으로 롤백되지 않습니다.

2. 예외에 따라 롤백 제어

@Transactional(rollbackFor = Exception.class)
public void someMethod() throws Exception {
    // Exception 발생 시 롤백
}

@Transactional의 주의사항

1. 프록시 객체를 통해 동작

  • 자기 자신 호출 문제: @Transactional이 적용된 메서드를 같은 클래스 내에서 호출하면 프록시를 거치지 않아 트랜잭션이 적용되지 않습니다.
  • 해결 방법 : 트랜잭션이 필요한 메서드를 별도의 빈으로 분리하거나, AOP 설정을 수정합니다.

2. 데이터베이스 지원

트랜잭션 격리 수준이나 롤백 동작은 사용하는 데이터베이스에 따라 다를 수 있습니다.

3. 읽기 전용 주의

  • readOnly = true로 설정했더라도 일부 데이터베이스는 쓰기 작업을 허용합니다. 개발자가 이를 직접 검증해야 합니다.

4. 트랜잭션 경계

  • 트랜잭션 경계(시작과 종료)는 메서드 호출 시점에 따라 결정됩니다. 비즈니스 로직이 예상보다 길면 성능 문제가 발생할 수 있습니다.

📌@Transactional은 트랜잭션 관리를 간소화하고 데이터베이스의 일관성을 유지하는 데 필수적입니다. 올바른 전파, 격리 수준, 예외 처리 설정을 통해 안정적이고 효율적인 애플리케이션을 개발할 수 있습니다. 하지만 트랜잭션이 항상 성능 부담을 동반하므로 필요하지 않은 경우에는 사용을 피하는 것이 좋습니다.

0개의 댓글