Spring :: @Transactional

태그
Spring
Database
날짜
2024/11/20
2 more properties

Transaction

DB의 상태를 변경시키기 위해 수행하는 작업 단위이다.

Transaction의 특징

원자성 (Atomicity)

Transaction의 연산은 DB에 모두 반영되거나, 혹은 모두 반영되지 않아야 한다.
Transaction안의 모든 명령은 반드시 완벽하게 수행되어야한다.
하나의 오류라도 발생한다면, Transaction 전부 취소되어야 한다.

일관성 (Consistency)

Transaction이 성공적으로 완료되면, 일관성 있는 DB 상태로 변환한다.
System이 가지고 있는 고정요소는 Transaction 수행 전과 후의 상태가 같아야 한다.

독립성 (Isolation)

둘 이상의 Transaction이 동시에 실행되는 경우, 다른 Transaction이 연산에 끼어들 수 없다.
수행중인 Transaction은 완전히 완료될 때 까지 다른 Transaction에서 수행 결과를 참조할 수 없다.

지속성 (Durability)

성공적으로 완료된 Transaction의 결과는 영구적으로 반영되어야 한다.

Transaction의 연산 - Commit & Rollback

Commit - 하나의 Transaction이 성공적으로 끝났으며, DB가 일관성있는 상태로 유지될 때, Transaction이 마무리되었다는 것을 Transaction Manager에게 알리기 위한 연산.
Rollback - Transaction 처리가 비정상적으로 종료된 경우, Transaction을 다시 시작하거나, 연산한 결과를 취소시킨다.

Spring에서 Transaction 적용

Spring에선 Annotation 방식의 Transaction 처리를 지원한다.
@Transactional을 선언하여 사용한다.
Class 또는 Method 위에 @Transactional을 붙이면, Transaction 기능이 적용된 Proxy 객체가 생성되며, Transaction 수행 여부에 따라 Commit 또는 Rollback 작업을 수행한다.

@Transactional의 동작 원리

@Transactional은 Spring AOP를 통해 구현되어있다.
Class 혹은 Method에 @Transactional이 선언되면, 해당 Class에 Transaction이 적용된 Proxy 객체 생성.
Proxy 객체는 @Transactional이 포함된 Method가 호출되면, Transaction을 시작하고, Commit 또는 Rollback을 수행한다.
CheckedException 또는 예외가 발생하지 않으면, Commit.
UncheckException이 발생하면, Rollback.

주의점

1.
우선순위
@Transactional은 우선순위를 가지고 있다.
Class Method → Class → Interface Method → Interface
→ 공통적인 Transaction 규칙은 Class, 예외적인 규칙은 Method에 선언하는 식으로 구성할 수 있다.
또한, Interface보다 Class에 사용하는 것을 권고 하고있다.
Spring recommends that you only annotate concrete classes (and methods of concrete classes) with the @Transactional annotation, as opposed to annotating interfaces. You certainly can place the @Transactional annotation on an interface (or an interface method), but this works only as you would expect it to if you are using interface-based proxies. The fact that Java annotations are not inherited from interfaces means that if you are using class-based proxies (proxy-target-class=”true”) or the weaving-based aspect (mode=”aspectj”), then the transaction settings are not recognized by the proxying and weaving infrastructure, and the object will not be wrapped in a transactional proxy, which would be decidedly bad.
Spring은 인터페이스에 주석을 추가하는 대신 @Transactional 주석으로 구체적인 클래스 (및 구체적인 클래스의 메서드)에만 주석을 달도록 권장합니다. 인터페이스 (또는 인터페이스 메소드)에 @Transactional 어노테이션을 배치 할 수 있지만 이는 인터페이스 기반 프록시를 사용하는 경우 예상 한 대로만 작동합니다. Java 주석이 인터페이스에서 상속되지 않는다는 사실은 클래스 기반 프록시 (proxy-target-class = “true”) 또는 위빙 기반 측면 (mode = “aspectj”)을 사용하는 경우 트랜잭션 설정이 다음과 같음을 의미합니다. 프록시 및 위빙 인프라에 의해 인식되지 않으며 객체가 트랜잭션 프록시에 래핑되지 않으므로 확실히 나쁠 것입니다.
Interface나 Interface의 Method에 적용할 수 있지만, Interface 기반 Proxy에서만 유효한 Transaction 설정이 된다.
Java Annotation은 Interface로부터 상속되지 않기 때문에, Class 기반 Proxy 또는 AspectJ기반에서 Transaction 설정을 인식 할 수 없다.
2.
Transaction의 Mode
@Transactional은 2가지 Mode가 있다.
a.
Proxy Mode (Default)
b.
AspectJ Mode
Proxy Mode는 다음과 같은 주의점이 있다.
반드시 public Method에 적용되어야 한다.
다른 접근제한자를 가진 Method에 선언하더라도 동작하지 않는다.
Non-public Method에 적용하고 싶다면 AspectJ Mode도 고려해야 한다.
@Transactional이 적용되지 않은 public Method가 @Transactional이 적용된 Method를 호출할 경우, 동작하지 않는다.

@Transactional 설정

속성
타입
설명
value
String
사용할 Transaction 관리자
propagation
enum: Propagation
선택적 전파 설정
isolation
enum: Isolation
선택적 격리 설정
readOnly
boolean
읽기 & 쓰기 / 읽기 전용 Transaction
timeout
int (sec)
Transaction Timeout 설정
rollbackFor
Throwable로 부터 얻을 수 있는 Class 객체 배열
Rollback이 수행되어야하는, 선택적인 예외 Class의 배열
rollbackForClassName
Throwable로 부터 얻을 수 있는 Class 이름 배열
Rollback이 수행되어야하는, 선택적인 예외 Class 이름의 배열
noRollbackFor
Throwable로 부터 얻을 수 있는 Class 객체 배열
Rollback이 수행되지 않아야하는, 선택적인 예외 Class의 배열
noRollbackForClassName
Throwable로 부터 얻을 수 있는 Class 이름 배열
Rollback이 수행되지 않아야하는, 선택적인 예외 Class 이름의 배열

다중 Transaction Manager

필요에 따라 다수의 독립된 Transaction Manager를 사용할 수 있다.
@Transactional의 value 속성에 사용할 PlatformTransactionManager를 지정하면 된다.
PlatformTransactionManager는 Spring이 제공하는 Transaction 관리 Interface이다.
Interface의 구현체에는 JDBC, Hibernate 등이 있는데, 이는 Transaction이 실제 작동할 환경이다.
→ 반드시 알맞은 PlatformTransactionManager 구현체가 정의되어 있어야 한다.
다중 Transaction Manager는 value 속성에 Bean의 Id 또는 qualifier 값을 지정한다.
public class TransactionService { @Transactional("transactionManagerA") public void getUser() { ... } @Transactional("transactionManagerB") public void addUser() { ... } }
Java
복사