※ 스프링 공식 문서를 바탕으로 글 작성하였습니다.
https://docs.spring.io/spring-framework/docs/current/javadoc
api/org/springframework/transaction/annotation/Transactional.html
Transactional (Spring Framework 6.1.13 API)
Describes a transaction attribute on an individual method or on a class. When this annotation is declared at the class level, it applies as a default to all methods of the declaring class and its subclasses. Note that it does not apply to ancestor classes
docs.spring.io
@Transactional 이란?
- @Transactional 어노테이션은 스프링 프레임워크에서 트랜잭션을 관리하기 위해 사용되는 중요한 요소이다.
- 이 어노테이션은 메소드나 클래스에 적용되어, 해당 메소드 또는 클래스의 모든 메소드 호출이 트랜잭션으로 처리되도록 한다. 클래스 수준에서 선언 시 모든 메소드에 기본적으로 적용된다.
- 상위 클래스의 메소드에는 적용되지 않으며, 하위 클래스에서 상위 클래스의 메소드를 참여시키려면 해당 메소드를 다시 선언해야한다.
- @Transactional의 역할은 데이터베이스 작업을 하나의 단위로 묶어, 모든 작업이 성공적으로 완료되거나 모두 롤백되도록 보장하는 것이다. 이를 통해 데이터의 일관성을 유지할 수 있다.
속성
- propagation:
- 설명: 트랜잭션의 전파 방식을 설정한다. 메소드가 호출될 때 어떤 트랜잭션을 사용할지를 정의한다.
- 타입: Propagation (enum)
- 기본값: Propagation.REQUIRED
- 옵션:
- REQUIRED: 현재 트랜잭션이 존재하면 그 트랜잭션을 사용하고, 없으면 새로운 트랜잭션을 생성한다.
- REQUIRES_NEW: 항상 새로운 트랜잭션을 생성하며, 기존 트랜잭션은 일시 중지된다.
- NESTED: 현재 트랜잭션 내에서 중첩 트랜잭션을 생성한다.
- SUPPORTS: 현재 트랜잭션이 있으면 그 트랜잭션을 사용하고, 없으면 트랜잭션 없이 실행한다.
- NOT_SUPPORTED: 항상 트랜잭션 없이 실행하며, 기존 트랜잭션은 일시 중지된다.
- MANDATORY: 현재 트랜잭션이 반드시 있어야 하며, 없으면 예외가 발생한다.
- NEVER: 트랜잭션 없이 실행해야 하며, 트랜잭션이 있으면 예외가 발생한다.
- isolation:
- 설명: 트랜잭션 격리 수준을 설정한다. 이는 트랜잭션 간의 상호 작용을 제어한다.
- 타입: Isolation (enum)
- 기본값: Isolation.DEFAULT
- 옵션:
- DEFAULT: 데이터베이스의 기본 격리 수준을 사용한다.
- READ_UNCOMMITTED: 다른 트랜잭션에서 커밋되지 않은 데이터를 읽을 수 있다.
- READ_COMMITTED: 커밋된 데이터만 읽을 수 있다.
- REPEATABLE_READ: 같은 트랜잭션 내에서 동일한 쿼리를 반복 실행할 때 항상 동일한 결과를 보장한다.
- SERIALIZABLE: 가장 높은 격리 수준으로, 트랜잭션이 순차적으로 실행되는 것처럼 동작한다.
- timeout:
- 설명: 트랜잭션이 시작된 후 주어진 시간(초)이 지나면 트랜잭션을 롤백한다.
- 타입: int
- 기본값: -1 (무제한 대기)
- readOnly:
- 설명: 트랜잭션이 읽기 전용인지 여부를 나타내는 플래그이다.
- 타입: boolean
- 기본값: false (읽기 전용이 아님)
- rollbackFor:
- 설명: 트랜잭션을 롤백할 예외 유형을 정의한다. 이 예외는 Throwable의 하위 클래스여야 한다.
- 타입: Class<? extends Throwable>[]
- rollbackForClassName:
- 설명: 트랜잭션을 롤백할 예외 이름 패턴을 정의한다. 예외는 Throwable의 하위 클래스여야 한다.
- 타입: String[]
- noRollbackFor:
- 설명: 롤백을 발생시키지 않을 예외 유형을 정의한다. 이 예외는 Throwable의 하위 클래스여야 한다.
- 타입: Class<? extends Throwable>[]
- noRollbackForClassName:
- 설명: 롤백을 발생시키지 않을 예외 이름 패턴을 정의한다. 예외는 Throwable의 하위 클래스여야 한다.
- 타입: String[]
- label:
- 설명: 트랜잭션에 대한 레이블을 정의한다. 이는 트랜잭션을 식별하거나 관련된 트랜잭션을 그룹화하는 데 유용하다.
- 타입: String[]
- 용도: 로깅 및 모니터링 도구에서 트랜잭션을 구분하는 데 사용될 수 있다.
- * 트랜잭션 레이블이란 => 트랜잭션 레이블은 특정 트랜잭션을 식별하거나 관련된 트랜잭션을 그룹화하는 데 사용되는 문자열.
- 주로 로깅이나 모니터링 도구에서 트랜잭션을 구분하기 위해 사용된다.
- 여러 트랜잭션이 동일한 방식으로 처리되거나 관련 있는 경우 레이블을 통해 그룹화할 수 있다.
- transactionManager:
- 설명: 특정 트랜잭션 매니저를 지정하는 값이다.
- 타입: String
- * 트랜잭션 매니저 => 트랜잭션 매니저는 트랜잭션을 관리하는 컴포넌트이다.
- 여러 데이터 소스나 데이터베이스를 사용하는 경우, 각 데이터 소스에 맞는 트랜잭션 매니저를 지정할 수 있다.
- Spring에서는 여러 종류의 트랜잭션 매니저를 제공하며, 주로 사용하는 것에는 DataSourceTransactionManager, JpaTransactionManager, HibernateTransactionManager 등이 있다.
- 커스텀하여 별도로 정의할 수도 있다.
- value:
- 설명: transactionManager()의 별칭이다.
- 타입: String
// transactionManager로 이렇게 작성하는 대신
@Transactional(transactionManager = "myTransactionManager")
// value로 바꾸어서 작성할 수 있다.
@Transactional(value = "myTransactionManager")
속성 적용 예시
모든 속성을 적용해 보았다.
- propagation: Propagation.REQUIRED로 설정하여 현재 트랜잭션이 존재하면 그 트랜잭션을 사용하고, 없으면 새로운 트랜잭션을 생성.
- isolation: Isolation.READ_COMMITTED로 설정하여 커밋된 데이터만 읽을 수 있도록 하였다.
- timeout: 30초 후에 트랜잭션 타임아웃.
- readOnly: false로 설정하여 데이터 수정이 가능하도록 하였다.
- rollbackFor: 모든 Exception이 발생할 경우 트랜잭션을 롤백하도록 설정.
- noRollbackFor: IllegalArgumentException이 발생해도 롤백하지 않도록 설정.
- rollbackForClassName: 클래스 이름을 통해 java.lang.Exception이 발생할 경우 롤백하도록 설정.
- noRollbackForClassName: 클래스 이름을 통해 java.lang.IllegalArgumentException이 발생해도 롤백하지 않도록 설정.
- label: "userTransaction"과 "critical"이라는 레이블을 부여하여 트랜잭션을 식별할 수 있다.
- transactionManager: "myTransactionManager"라는 내가 별도로 정의한 트랜잭션 매니저를 지정하였다.
@Transactional의 기본값
별도로 아무 설정하지 않았을 때의 기본 옵션을 알아보자.
1. propagation : REQUIRED: 현재 트랜잭션이 존재하면 그 트랜잭션을 사용하고, 없으면 새로운 트랜잭션을 생성.
2. isolation: DEFAULT: 데이터베이스의 기본 격리 수준을 사용한다.
* 주요 db들에 사용되는 isolation level
MySQL:
기본 격리 수준: Repeatable Read
지원하는 격리 수준: Read Uncommitted, Read Committed, Repeatable Read, Serializable
PostgreSQL:
기본 격리 수준: Read Committed
지원하는 격리 수준: Read Uncommitted, Read Committed, Repeatable Read, Serializable
Oracle:
기본 격리 수준: Read Committed
지원하는 격리 수준: Read Committed, Serializable (Oracle은 Read Uncommitted를 지원하지 않음)
SQL Server:
기본 격리 수준: Read Committed
지원하는 격리 수준: Read Uncommitted, Read Committed, Repeatable Read, Serializable, Snapshot(스프링은 지원하지 않음)
3. timeout : TransactionDefinition.TIMEOUT_DEFAULT (-1) => 무제한 대기
4. readOnly : false => 조회뿐만 아니라 INSERT, UPDATE, DELETE와 같은 모든 데이터 수정 작업 가능.
그 외 옵션은 모두 빈 값으로 설정되어 있었다.
코드 적용
조회용과 그 외의 용도로 나누어서 @Transaction을 붙였다.
대부분은 그냥 기본 @Transactional을 사용했지만, 조회용은 readOnly=true를 적용하였는데 그 이유는 아래와 같다.
- 조회용
- true 설정을 하면 해당 트랜잭션은 읽기 전용으로 설정되며 코드를 자세히 보지 않아도 조회목적의 서비스라는 걸 알 수 있게 한다.
- true 설정 시, JPA는 이 트랜잭션 내에서 사용되는 entity가 조회용으로 인식하고, 변경 감지를 위한 snapshot을 보관하지 않기 때문에 메모리가 절약되는 이점이 있다. (참고 블로그 : https://hungseong.tistory.com/74)
'개발 공부 > Java & Spring' 카테고리의 다른 글
[SpringBoot] application.yaml 환경별 Profile 설정하기 (0) | 2024.10.12 |
---|---|
스프링에서 예외처리를 하는 방법 (ExceptionHandler, RestControllerAdvice) (0) | 2024.08.23 |
DTO vs Map 장점과 단점은? (1) | 2024.08.14 |
27. File (0) | 2023.04.17 |
26. 표준 입출력과 RandomAccessFile (0) | 2023.04.16 |