포괄적인 트랜잭션 지원은 Spring Framework를 사용하는 가장 강력한 이유 중 하나이다. Spring Framework는 다음과 같은 이점을 제공하는 트랜잭션 관리를 위한 일관된 추상화를 제공한다.
- JTA(Java Transaction API), JDBC, Hibernate 및 JPA(Java Persistence API)와 같은 다양한 트랜잭션 API에서 일관된 프로그래밍 모델
- 선언적 트랜잭션 관리 지원
- 프로그래밍 방식 트랜잭션 관리 지원
- Spring의 데이터 접근 추상화와의 뛰어난 통합
Spring Transaction 지원 모델에 대해 알아보기 전에, 이전의 Transaction 처리 방식에 대해 알아보자.
전통적인 Java EE 개발자는 트랜잭션 관리를 하기 위해선 두가지중 하나를 선택해야했다.
- Global Transactions
- Local Transactions
-
Global Transactions는 RDB나 MQ 등의 여러 리소스에서 작업할 수 있는 통용되는 트랜잭션 관리 방법이다. 주로 JTA를 통해 글로벌 트랜잭션을 관리한다. 또한 JTA의 UserTransaction은 일반적으로 JNDI에서 제공되어야 한다. 즉, JTA를 사용하려면 JNDI도 사용해야 한다.
-
JTA는 일반적으로 응용 프로그램 서버 환경에서만 사용할 수 있으므로 전역 트랜잭션을 사용하면 응용 프로그램 코드의 잠재적인 재사용이 제한된다. 그렇기 때문에 JTA는 햔재 잘 쓰이지 않는 기술이다.
-
이전에 Global Transactions를 사용하는데 선호되었던 방법은 EJB CMT (Container Managed Transaction)였다. CMT는 선언적 트랜잭션 관리의 한 형태인데, 이 CMT는 JTA 및 응용 프로그램 서버 환경에 묶여 있어 EJB와 꼭 함께 사용해야만 한다.
하지만 EJB는 너무나도 많은 단점을 가지고 있기 때문에, 현재는 CMT 또한 잘 쓰이지 않는다.
- Local Transactions는 각 데이터나 기술에 맞는 트랜잭션 방식을 사용하는 것이다. 각 기술에 특화되어있기 때문에 그에 따라 코드를 다 따로 작성해줘야한다. 또, 애플리케이션 서버는 트랜잭션 관리에 관여하지 않기 때문에 여러 리소스에 대한 정확성을 보장하는 데 도움이 되지 않는다.
-
Spring은 Global Transactions와 Local Transactions의 문제를 해결한다! Spring은 개발자가 개발 환경에 구애받지 않고 일관된 프로그래밍 모델을 사용할 수 있도록 해준다.
-
프로그래밍 방식의 트랜잭션 관리를 통해 개발자는 기본 트랜잭션 인프라에서, 실행할 수 있는 Spring 트랜잭션 추상화로 작업할 수 있다. 트랜잭션 관리라는 구체적인 부분과 다른 로직이 구분되기 때문에 DIP적이다.
-
Spring Framework는 선언적 트랜잭션 관리와 프로그래밍 트랜잭션 관리를 모두 제공하며, 대부분의 경우에는 선언적 트랜잭션 관리가 선호된다.
Spring 트랜잭션 추상화에서 가장 중요한 것은, 트랜잭션 전략이라는 개념이다.
이 트랜잭션 전략은 TransactionManager
에 의해 정의된다.
트랜잭션 전략중 주로 쓰이는 것은, PlatformTransactionManager
인터페이스가 있다. 인터페이스이기 때문에 상황에 따라 맞는 구현체를 선택할 수 있다.
public interface TransactionManager {
}
public interface PlatformTransactionManager extends TransactionManager {
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
여기서 getTransaction(...)
메소드는 TransactionDefinition
을 파라미터로 받아 TransactionStatus
를 반환한다.
TransactionStatus
는 새 트랜잭션, 혹은 현재 쓰레드에 이미 존재하는 트랜잭션의 정보를 나타내며,
TransactionDefinition
인터페이스는 트랜잭션의 다양한 속성을 지정할 수 있다.
TransactionDefinition
에서 지정할 수 있는 속성으로는 다음과 같은 것들이 있다.
-
전파 : 트랜잭션 범위 안에 있는 모든 코드는 트랜잭션에 묶여 실행된다. 하지만 트랜잭션 컨텍스트가 이미 존재할 때는 트랜잭션 메소드가 동작하는 방식을 따로 지정할 수 있다.
일반적인 경우에는 코드가 기존 트랜잭션에서 계속 실행되지만, 원하는 경우에는 기존 트랜잭션을 일시 중단하고 새 트랜잭션을 생성할 수 있다. 트랜잭션 전파 문서에서 더 알아보자
-
격리수준 : 트랜잭션이 다른 트랜잭션의 작업과 격리되는 정도이다.
READ_UNCOMMITTED
,READ_COMMITTED
,READ_COMMITTED
,SERIALIZABLE
등의 설정값이 있다. 또는, RDBMS의 기본값에 따를 수도 있다. -
시간 제한 : 트랜잭션이 일정 시간 이상 수행되면, 자동으로 롤백되도록 설정할 수 있다.
-
읽기 전용 여부 : 트랜잭션을 Read-Only로 설정하여 일부 기능을 최적화할 수 있다. Hibernate를 사용하는 경우에 유용하게 사용될 수 있다.
이러한 설정은 표준 트랜잭션 개념을 반영한다. 트랜잭션에 대해 자세히 알고 싶다면 이 문서를 참조할 수 있다.
출처: https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#transaction