이번글은 공식 문서에서 소개하는 Transaction Management에 대해 정리했습니다.
범위 : Choosing Between Programmatic and Declarative Transaction Management ~Further Resource
Choosing Between Programmatic and Declarative Transaction Management
Programmatic transaction management is usually a good idea only if you have a small number of transactional operations. For example, if you have a web application that requires transactions only for certain update operations, you may not want to set up transactional proxies by using Spring or any other technology. In this case, using the TransactionTemplate may be a good approach. Being able to set the transaction name explicitly is also something that can be done only by using the programmatic approach to transaction management.
프로그램 방식의 트랜잭션 관리는 보통 트랜잭션 작업의 수가 적을 때만 좋은 방법입니다. 예를 들어, 특정 업데이트 작업에만 트랜잭션이 필요한 웹 애플리케이션의 경우 Spring이나 다른 기술을 사용하여 트랜잭션 프록시를 설정하지 않을 수도 있습니다.
이 경우 TransactionTemplate을 사용하는 것이 좋은 접근 방법이 될 수 있습니다. 또한, 트랜잭션 이름을 명시적으로 설정할 수 있는 것도 프로그래밍 방식의 트랜잭션 관리로만 가능한 일입니다.
On the other hand, if your application has numerous transactional operations, declarative transaction management is usually worthwhile. It keeps transaction management out of business logic and is not difficult to configure. When using the Spring Framework, rather than EJB CMT, the configuration cost of declarative transaction management is greatly reduced.
반면, 애플리케이션에 수많은 트랜잭션 작업이 있다면, 선언적 트랜잭션 관리가 보통 가치가 있습니다. 이는 트랜잭션 관리를 비즈니스 로직에서 분리하며 구성하기 어렵지 않습니다. Spring Framework를 사용할 때는 EJB CMT 대신 선언적 트랜잭션 관리의 구성 비용이 크게 줄어듭니다.
Transaction-bound Events
As of Spring 4.2, the listener of an event can be bound to a phase of the transaction. The typical example is to handle the event when the transaction has completed successfully. Doing so lets events be used with more flexibility when the outcome of the current transaction actually matters to the listener.
Spring 4.2부터 이벤트 리스너를 트랜잭션의 특정 단계에 바인딩할 수 있습니다. 일반적인 예로는 트랜잭션이 성공적으로 완료되었을 때 이벤트를 처리하는 경우가 있습니다. 이렇게 하면 현재 트랜잭션의 결과가 실제로 리스너에게 중요할 때, 이벤트를 보다 유연하게 사용할 수 있습니다.
You can register a regular event listener by using the @EventListener annotation. If you need to bind it to the transaction, use @TransactionalEventListener. When you do so, the listener is bound to the commit phase of the transaction by default.
@EventListener 애노테이션을 사용하여 일반 이벤트 리스너를 등록할 수 있습니다. 만약 이를 트랜잭션에 바인딩해야 한다면, @TransactionalEventListener를 사용하세요. 이 경우, 리스너는 기본적으로 트랜잭션의 커밋 단계에 바인딩됩니다.
The next example shows this concept. Assume that a component publishes an order-created event and that we want to define a listener that should only handle that event once the transaction in which it has been published has committed successfully. The following example sets up such an event listener:
다음 예제는 이 개념을 보여줍니다. 어떤 컴포넌트가 order-created 이벤트를 발행하고, 그 이벤트가 발행된 트랜잭션이 성공적으로 커밋된 후에만 해당 이벤트를 처리해야 하는 리스너를 정의하고자 한다고 가정합니다. 다음 예제는 그러한 이벤트 리스너를 설정하는 방법을 보여줍니다.
@Component
public class MyComponent {
@TransactionalEventListener
public void handleOrderCreatedEvent(CreationEvent<Order> creationEvent) {
// ...
}
}
The @TransactionalEventListener annotation exposes a phase attribute that lets you customize the phase of the transaction to which the listener should be bound. The valid phases are BEFORE_COMMIT, AFTER_COMMIT (default), AFTER_ROLLBACK, as well as AFTER_COMPLETION which aggregates the transaction completion (be it a commit or a rollback).
@TransactionalEventListener 어노테이션은 리스너가 바인딩되어야 하는 트랜잭션의 단계를 사용자 정의할 수 있는 phase 속성을 제공합니다. 유효한 단계는 BEFORE_COMMIT, AFTER_COMMIT(기본값), AFTER_ROLLBACK, 그리고 트랜잭션 완료(커밋이든 롤백이든 상관없이)를 집계하는 AFTER_COMPLETION입니다.
If no transaction is running, the listener is not invoked at all, since we cannot honor the required semantics. You can, however, override that behavior by setting the fallbackExecution attribute of the annotation to true.
실행 중인 트랜잭션이 없으면, 필수 의미 체계를 충족할 수 없으므로 리스너가 전혀 호출되지 않습니다. 하지만 어노테이션의 fallbackExecution 속성을 true로 설정하면 해당 동작을 재정의할 수 있습니다.
즉, 트랜잭션이 진행 중이지 않으면 리스너가 "트랜잭션 완료" 같은 특정 상황을 감지할 수 없기 때문에 아예 실행되지 않는다는 뜻입니다. 하지만 fallbackExecution 속성을 true로 설정하면, 이런 경우에도 리스너를 강제로 실행할 수 있도록 설정할 수 있다는 의미입니다.
As of 6.1, @TransactionalEventListener can work with thread-bound transactions managed by PlatformTransactionManager as well as reactive transactions managed by ReactiveTransactionManager. For the former, listeners are guaranteed to see the current thread-bound transaction. Since the latter uses the Reactor context instead of thread-local variables, the transaction context needs to be included in the published event instance as the event source. See the TransactionalEventPublisher javadoc for details.
6.1부터, @TransactionalEventListener는 PlatformTransactionManager가 관리하는 스레드 바인딩 트랜잭션과 ReactiveTransactionManager가 관리하는 반응형 트랜잭션 모두에서 작동할 수 있습니다. 전자의 경우, 리스너는 현재 스레드에 바인딩된 트랜잭션을 확실하게 인식할 수 있습니다. 반면 후자의 경우, 스레드 로컬 변수가 아닌 Reactor 컨텍스트를 사용하므로, 트랜잭션 컨텍스트를 이벤트 소스로서 발행된 이벤트 인스턴스에 포함시켜야 합니다. 자세한 내용은 TransactionalEventPublisher javadoc을 참조하세요.\
즉, Spring 6.1부터 @TransactionalEventListener는 두 가지 방식의 트랜잭션을 모두 지원합니다.
스레드 바인딩 트랜잭션 (Thread-bound Transactions): 전통적인 방식의 트랜잭션은 특정 스레드에 묶여 있기 때문에, 이벤트 리스너가 자동으로 현재 실행 중인 트랜잭션 정보를 인식할 수 있습니다.
반응형 트랜잭션 (Reactive Transactions): 반응형 트랜잭션은 스레드 로컬 변수를 사용하지 않고 Reactor 컨텍스트를 사용합니다. 때문에, 트랜잭션 컨텍스트가 이벤트 객체에 포함되어야만 리스너가 그 정보를 확인할 수 있습니다.
즉, 일반 트랜잭션에서는 별도의 처리가 필요 없지만, 반응형 트랜잭션에서는 이벤트를 발행할 때 트랜잭션 정보를 함께 전달해줘야 한다는 의미입니다.
Application server-specific integration
Spring’s transaction abstraction is generally application server-agnostic. Additionally, Spring’s JtaTransactionManager class (which can optionally perform a JNDI lookup for the JTA UserTransaction and TransactionManager objects) autodetects the location for the latter object, which varies by application server. Having access to the JTA TransactionManager allows for enhanced transaction semantics — in particular, supporting transaction suspension. See the JtaTransactionManager javadoc for details.
Spring의 트랜잭션 추상화는 일반적으로 애플리케이션 서버에 구애받지 않습니다. 또한, Spring의 JtaTransactionManager 클래스는 (선택적으로 JNDI 조회를 통해 JTA UserTransaction 및 TransactionManager 객체를 찾을 수 있으며) 후자의 객체 위치를 자동으로 감지하는데, 이는 애플리케이션 서버마다 다릅니다. JTA TransactionManager에 접근할 수 있으면 향상된 트랜잭션 의미 체계를 제공할 수 있으며, 특히 트랜잭션 중단을 지원합니다. 자세한 내용은 JtaTransactionManager javadoc을 참조하세요.
Spring’s JtaTransactionManager is the standard choice to run on Jakarta EE application servers and is known to work on all common servers. Advanced functionality, such as transaction suspension, works on many servers as well (including GlassFish, JBoss and Geronimo) without any special configuration required.
Spring의 JtaTransactionManager는 Jakarta EE 애플리케이션 서버에서 실행하기 위한 표준 선택이며, 모든 일반적인 서버에서 작동하는 것으로 알려져 있습니다. GlassFish, JBoss, Geronimo를 포함한 많은 서버에서 특별한 구성 없이도 트랜잭션 중단과 같은 고급 기능이 작동합니다.
JTA(Java Transaction API)는 여러 데이터 소스나 리소스에 걸친 트랜잭션을 관리할 수 있도록 해주는 Java의 표준 API입니다. 이를 통해 애플리케이션은 분산 트랜잭션을 지원받으며, 여러 리소스(예: 데이터베이스, 메시징 시스템 등) 간의 트랜잭션을 일관되게 처리할 수 있습니다. 보통 기업용 애플리케이션 서버(Jakarta EE 등)에서 많이 사용됩니다.
Solutions to Common Problems
Using the Wrong Transaction Manager for a Specific DataSource
Use the correct PlatformTransactionManager implementation based on your choice of transactional technologies and requirements. Used properly, the Spring Framework merely provides a straightforward and portable abstraction. If you use global transactions, you must use the org.springframework.transaction.jta.JtaTransactionManager class (or an application server-specific subclass of it) for all your transactional operations. Otherwise, the transaction infrastructure tries to perform local transactions on such resources as container DataSource instances. Such local transactions do not make sense, and a good application server treats them as errors.
선택한 트랜잭션 기술과 요구 사항에 따라 올바른 PlatformTransactionManager 구현체를 사용하십시오. 적절하게 사용된다면, Spring Framework는 단순하고 이식 가능한 추상화만을 제공합니다. 만약 글로벌 트랜잭션을 사용한다면, 모든 트랜잭션 작업에 대해 org.springframework.transaction.jta.JtaTransactionManager 클래스(또는 해당 애플리케이션 서버 전용 서브클래스)를 사용해야 합니다. 그렇지 않으면, 트랜잭션 인프라는 컨테이너 DataSource 인스턴스와 같은 리소스에서 로컬 트랜잭션을 수행하려고 시도합니다. 이러한 로컬 트랜잭션은 의미가 없으며, 좋은 애플리케이션 서버에서는 이를 오류로 처리합니다.
Further Resource
For more information about the Spring Framework’s transaction support, see:
- Distributed transactions in Spring, with and without XA is a JavaWorld presentation in which Spring’s David Syer guides you through seven patterns for distributed transactions in Spring applications, three of them with XA and four without.
- Java Transaction Design Strategies is a book available from InfoQ that provides a well-paced introduction to transactions in Java. It also includes side-by-side examples of how to configure and use transactions with both the Spring Framework and EJB3.
Spring Framework의 트랜잭션 지원에 대해 더 자세히 알아보려면 다음을 참조하세요:
Distributed transactions in Spring, with and without XA는 JavaWorld 프레젠테이션으로, Spring의 David Syer가 XA를 사용하는 경우 3가지, 사용하지 않는 경우 4가지, 총 7가지의 분산 트랜잭션 패턴을 통해 Spring 애플리케이션에서 분산 트랜잭션을 다루는 방법을 안내합니다.
Java Transaction Design Strategies는 InfoQ에서 제공하는 책으로, Java에서의 트랜잭션에 대한 적절한 속도의 소개를 제공하며, Spring Framework와 EJB3 모두에서 트랜잭션을 구성하고 사용하는 방법에 대한 나란히 배치된 예제들을 포함하고 있습니다.
'공식문서' 카테고리의 다른 글
[Spring Docs] DAO Support (0) | 2025.03.25 |
---|---|
Garbage Collector #3 (0) | 2025.03.24 |
[Spring Docs] Programmatic Transaction Management #4 (0) | 2025.03.20 |
[Spring Docs] Transaction Management #3 (0) | 2025.03.19 |
[Spring Docs] Transaction Management #2 (0) | 2025.03.18 |