LostCatBox

Spring Transactional에 대한 5가지 옵션

Word count: 474Reading time: 2 min
2024/06/16 Share

왜?

  • 코드리뷰 당시에 @Transactional 에 대한 5가지 옵션에 대해서 각 설명을 해야하였으며, 지식의 부족함을 느꼈다.
  • @Transactional(readonly=true) 등의 옵션에 대해 각 특성을 확인해보자

@Transactional의 주요 옵션들

  1. propagation: 트랜잭션 전파 방식을 정의합니다.
    • REQUIRED: 현재 트랜잭션이 존재하면 참여하고, 없으면 새로운 트랜잭션을 시작합니다.
    • REQUIRES_NEW: 항상 새로운 트랜잭션을 시작합니다. 현재 트랜잭션이 존재하면 일시 중단됩니다.
    • NESTED: 중첩된 트랜잭션을 시작합니다.
    • MANDATORY: 현재 트랜잭션이 존재해야 합니다. 그렇지 않으면 예외가 발생합니다.
    • SUPPORTS: 트랜잭션이 존재하면 참여하고, 그렇지 않으면 트랜잭션 없이 실행됩니다.
    • NOT_SUPPORTED: 트랜잭션 없이 실행됩니다. 현재 트랜잭션이 존재하면 일시 중단됩니다.
    • NEVER: 트랜잭션이 존재하면 예외가 발생합니다.
  2. isolation: 트랜잭션의 격리 수준을 정의합니다.
    • DEFAULT: 기본 데이터베이스의 격리 수준을 사용합니다.
    • READ_UNCOMMITTED: 가장 낮은 격리 수준, 다른 트랜잭션에서 커밋되지 않은 변경 사항도 읽을 수 있습니다.
    • READ_COMMITTED: 커밋된 데이터만 읽을 수 있습니다.
    • REPEATABLE_READ: 동일한 트랜잭션 내에서 동일한 데이터를 여러 번 읽어도 항상 같은 결과를 반환합니다.
    • SERIALIZABLE: 가장 높은 격리 수준, 트랜잭션을 직렬화하여 실행합니다.
  3. timeout: 트랜잭션이 롤백되기 전 대기할 최대 시간을 초 단위로 지정합니다.
  4. readOnly: 트랜잭션이 읽기 전용인지 여부를 지정합니다.
  5. rollbackFor: 지정된 예외가 발생하면 롤백합니다.
  6. noRollbackFor: 지정된 예외가 발생해도 롤백하지 않습니다.

예시 코드

아래는 위의 옵션들을 사용한 예제 코드입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
java
코드 복사
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class ExampleService {

@Autowired
private ExampleRepository exampleRepository;

// 트랜잭션이 없으면 새로운 트랜잭션을 시작하고, 있으면 참여
@Transactional(propagation = Propagation.REQUIRED)
public void requiredTransactionMethod() {
// 비즈니스 로직
exampleRepository.save(new ExampleEntity("data1"));
}

// 항상 새로운 트랜잭션을 시작
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void requiresNewTransactionMethod() {
// 비즈니스 로직
exampleRepository.save(new ExampleEntity("data2"));
}

// 중첩된 트랜잭션을 시작
@Transactional(propagation = Propagation.NESTED)
public void nestedTransactionMethod() {
// 비즈니스 로직
exampleRepository.save(new ExampleEntity("data3"));
}

// 읽기 전용 트랜잭션
@Transactional(readOnly = true)
public ExampleEntity readOnlyTransactionMethod(Long id) {
// 비즈니스 로직
return exampleRepository.findById(id).orElse(null);
}

// 트랜잭션 타임아웃 설정 (5초)
@Transactional(timeout = 5)
public void timeoutTransactionMethod() {
// 비즈니스 로직
exampleRepository.save(new ExampleEntity("data4"));
}

// 특정 예외 발생 시 롤백
@Transactional(rollbackFor = CustomException.class)
public void rollbackForTransactionMethod() throws CustomException {
// 비즈니스 로직
exampleRepository.save(new ExampleEntity("data5"));
throw new CustomException("Rollback this transaction");
}

// 특정 예외 발생 시 롤백하지 않음
@Transactional(noRollbackFor = CustomException.class)
public void noRollbackForTransactionMethod() throws CustomException {
// 비즈니스 로직
exampleRepository.save(new ExampleEntity("data6"));
throw new CustomException("Don't rollback this transaction");
}
}

class CustomException extends Exception {
public CustomException(String message) {
super(message);
}
}

이 예제 코드에서는 @Transactional 어노테이션의 다양한 옵션을 사용하여 트랜잭션의 전파 방식, 격리 수준, 타임아웃, 읽기 전용 여부, 롤백 조건 등을 설정한 메서드들을 보여줍니다. 각 옵션을 통해 필요한 트랜잭션 동작을 구체적으로 제어할 수 있습니다.

CATALOG
  1. 1. 왜?
    1. 1.0.1. @Transactional의 주요 옵션들
    2. 1.0.2. 예시 코드