Programmatic Transaction Management
Spring Framework 提供了两种通过以下方式进行编程事务管理的方法:
-
The
TransactionTemplate
orTransactionalOperator
. -
A
TransactionManager
implementation directly.
Spring 团队通常建议将 TransactionTemplate
用于命令式流程中的编程事务管理,将 TransactionalOperator
用于反应式代码。第二种方法类似于使用 JTA UserTransaction
API,尽管异常处理不太麻烦。
Using the TransactionTemplate
TransactionTemplate
采用与其他 Spring 模板相同的方法,例如 JdbcTemplate
。它使用回调方法(使应用程序代码摆脱了执行样板获取和释放事务资源的麻烦),从而生成意图驱动的代码,即代码只关注想要做什么。
如下例所示,使用 |
必须在事务上下文中运行且明确使用 TransactionTemplate
的应用程序代码类似于以下示例。作为应用程序开发者,可以编写 TransactionCallback
实现(通常以匿名内部类的形式表示),其中包含需要在事务上下文中运行的代码。然后,可以将自定义 TransactionCallback
的实例传递给 TransactionTemplate
上公开的 execute(..)
方法。以下示例展示了如何操作:
-
Java
-
Kotlin
public class SimpleService implements Service {
// single TransactionTemplate shared amongst all methods in this instance
private final TransactionTemplate transactionTemplate;
// use constructor-injection to supply the PlatformTransactionManager
public SimpleService(PlatformTransactionManager transactionManager) {
this.transactionTemplate = new TransactionTemplate(transactionManager);
}
public Object someServiceMethod() {
return transactionTemplate.execute(new TransactionCallback() {
// the code in this method runs in a transactional context
public Object doInTransaction(TransactionStatus status) {
updateOperation1();
return resultOfUpdateOperation2();
}
});
}
}
// use constructor-injection to supply the PlatformTransactionManager
class SimpleService(transactionManager: PlatformTransactionManager) : Service {
// single TransactionTemplate shared amongst all methods in this instance
private val transactionTemplate = TransactionTemplate(transactionManager)
fun someServiceMethod() = transactionTemplate.execute<Any?> {
updateOperation1()
resultOfUpdateOperation2()
}
}
如果没有返回值,可以使用带有匿名类的方便的 TransactionCallbackWithoutResult
类,如下所示:
-
Java
-
Kotlin
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
updateOperation1();
updateOperation2();
}
});
transactionTemplate.execute(object : TransactionCallbackWithoutResult() {
override fun doInTransactionWithoutResult(status: TransactionStatus) {
updateOperation1()
updateOperation2()
}
})
回调中的代码可以通过调用提供的 TransactionStatus
对象上的 setRollbackOnly()
方法回滚事务,如下所示:
-
Java
-
Kotlin
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
try {
updateOperation1();
updateOperation2();
} catch (SomeBusinessException ex) {
status.setRollbackOnly();
}
}
});
transactionTemplate.execute(object : TransactionCallbackWithoutResult() {
override fun doInTransactionWithoutResult(status: TransactionStatus) {
try {
updateOperation1()
updateOperation2()
} catch (ex: SomeBusinessException) {
status.setRollbackOnly()
}
}
})
Specifying Transaction Settings
您可以在 TransactionTemplate
上指定事务设置(例如传播模式、隔离级别、超时等等),这可以通过编程方式或在配置中指定。默认情况下,TransactionTemplate
实例具有 default transactional settings。以下示例展示了对特定 TransactionTemplate:
的事务设置的程序化自定义
-
Java
-
Kotlin
public class SimpleService implements Service {
private final TransactionTemplate transactionTemplate;
public SimpleService(PlatformTransactionManager transactionManager) {
this.transactionTemplate = new TransactionTemplate(transactionManager);
// the transaction settings can be set here explicitly if so desired
this.transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
this.transactionTemplate.setTimeout(30); // 30 seconds
// and so forth...
}
}
class SimpleService(transactionManager: PlatformTransactionManager) : Service {
private val transactionTemplate = TransactionTemplate(transactionManager).apply {
// the transaction settings can be set here explicitly if so desired
isolationLevel = TransactionDefinition.ISOLATION_READ_UNCOMMITTED
timeout = 30 // 30 seconds
// and so forth...
}
}
以下示例使用 Spring XML 配置定义了一个具有某些自定义事务设置的 TransactionTemplate
:
<bean id="sharedTransactionTemplate"
class="org.springframework.transaction.support.TransactionTemplate">
<property name="isolationLevelName" value="ISOLATION_READ_UNCOMMITTED"/>
<property name="timeout" value="30"/>
</bean>
然后,可以将 sharedTransactionTemplate
注入到所需的多个服务中。
最后,TransactionTemplate
类的实例是线程安全的,因为实例不会维护任何会话状态。但是,TransactionTemplate
实例会维护配置状态。因此,尽管多个类可以共享 TransactionTemplate
的单个实例,但如果某个类需要使用具有不同设置的 TransactionTemplate
(例如,不同的隔离级别),则需要创建两个不同的 TransactionTemplate
实例。
Using the TransactionalOperator
TransactionalOperator
遵循的操作员设计类似于其他反应式操作员。它使用回调方法(使应用程序代码摆脱了执行样板获取和释放事务资源的麻烦),从而生成意图驱动的代码,即代码只关注想要做什么。
如下例所示,使用 |
必须在事务上下文中运行且明确使用 TransactionalOperator
的应用程序代码类似于以下示例:
-
Java
-
Kotlin
public class SimpleService implements Service {
// single TransactionalOperator shared amongst all methods in this instance
private final TransactionalOperator transactionalOperator;
// use constructor-injection to supply the ReactiveTransactionManager
public SimpleService(ReactiveTransactionManager transactionManager) {
this.transactionalOperator = TransactionalOperator.create(transactionManager);
}
public Mono<Object> someServiceMethod() {
// the code in this method runs in a transactional context
Mono<Object> update = updateOperation1();
return update.then(resultOfUpdateOperation2).as(transactionalOperator::transactional);
}
}
// use constructor-injection to supply the ReactiveTransactionManager
class SimpleService(transactionManager: ReactiveTransactionManager) : Service {
// single TransactionalOperator shared amongst all methods in this instance
private val transactionalOperator = TransactionalOperator.create(transactionManager)
suspend fun someServiceMethod() = transactionalOperator.executeAndAwait<Any?> {
updateOperation1()
resultOfUpdateOperation2()
}
}
TransactionalOperator
可以通过两种方式使用:
-
使用 Project Reactor 类型 (
mono.as(transactionalOperator::transactional)
) 的操作员样式 -
针对任何其他情况的回调样式 (
transactionalOperator.execute(TransactionCallback<T>)
)
回调中的代码可以通过调用提供的 ReactiveTransaction
对象上的 setRollbackOnly()
方法回滚事务,如下所示:
-
Java
-
Kotlin
transactionalOperator.execute(new TransactionCallback<>() {
public Mono<Object> doInTransaction(ReactiveTransaction status) {
return updateOperation1().then(updateOperation2)
.doOnError(SomeBusinessException.class, e -> status.setRollbackOnly());
}
}
});
transactionalOperator.execute(object : TransactionCallback() {
override fun doInTransactionWithoutResult(status: ReactiveTransaction) {
updateOperation1().then(updateOperation2)
.doOnError(SomeBusinessException.class, e -> status.setRollbackOnly())
}
})
Cancel Signals
在 Reactive Streams 中,Subscriber
可以取消其 Subscription
并停止其 Publisher
。Project Reactor 中以及 next()
,take(long)
, timeout(Duration)
这样的其他库中的操作员都可以发出取消。无法得知取消的原因,是由于错误还是仅仅是对进一步消费缺乏兴趣。从版本 5.3 开始,取消信号会导致回滚。因此,重要的是考虑从事务 Publisher
使用的下游操作员。特别是在 Flux
或其他多值 Publisher
的情况下,必须消耗全部输出才能使事务完成。
Specifying Transaction Settings
您可以为 TransactionalOperator
指定事务设置(例如传播模式、隔离级别、超时等等)。默认情况下,TransactionalOperator
实例具有 default transactional settings。以下示例展示了对特定 TransactionalOperator:
的事务设置的自定义
-
Java
-
Kotlin
public class SimpleService implements Service {
private final TransactionalOperator transactionalOperator;
public SimpleService(ReactiveTransactionManager transactionManager) {
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
// the transaction settings can be set here explicitly if so desired
definition.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
definition.setTimeout(30); // 30 seconds
// and so forth...
this.transactionalOperator = TransactionalOperator.create(transactionManager, definition);
}
}
class SimpleService(transactionManager: ReactiveTransactionManager) : Service {
private val definition = DefaultTransactionDefinition().apply {
// the transaction settings can be set here explicitly if so desired
isolationLevel = TransactionDefinition.ISOLATION_READ_UNCOMMITTED
timeout = 30 // 30 seconds
// and so forth...
}
private val transactionalOperator = TransactionalOperator(transactionManager, definition)
}
Using the TransactionManager
以下部分介绍了命令式和响应式事务管理器的编程用法。
Using the PlatformTransactionManager
对于命令式事务,你可以直接使用 org.springframework.transaction.PlatformTransactionManager
管理你的事务。要做到这一点,你需要通过 Bean 引用将你要使用的 PlatformTransactionManager
的实现传递给你的 Bean。然后,通过使用 TransactionDefinition
和 TransactionStatus
对象,你可以启动事务、回滚和提交。以下示例展示了如何执行此操作:
-
Java
-
Kotlin
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// explicitly setting the transaction name is something that can be done only programmatically
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = txManager.getTransaction(def);
try {
// put your business logic here
} catch (MyException ex) {
txManager.rollback(status);
throw ex;
}
txManager.commit(status);
val def = DefaultTransactionDefinition()
// explicitly setting the transaction name is something that can be done only programmatically
def.setName("SomeTxName")
def.propagationBehavior = TransactionDefinition.PROPAGATION_REQUIRED
val status = txManager.getTransaction(def)
try {
// put your business logic here
} catch (ex: MyException) {
txManager.rollback(status)
throw ex
}
txManager.commit(status)
Using the ReactiveTransactionManager
在使用响应式事务时,你可以直接使用 org.springframework.transaction.ReactiveTransactionManager
管理你的事务。要做到这一点,你需要通过 Bean 引用将你要使用的 ReactiveTransactionManager
的实现传递给你的 Bean。然后,通过使用 TransactionDefinition
和 ReactiveTransaction
对象,你可以启动事务、回滚和提交。以下示例展示了如何执行此操作:
-
Java
-
Kotlin
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// explicitly setting the transaction name is something that can be done only programmatically
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
Mono<ReactiveTransaction> reactiveTx = txManager.getReactiveTransaction(def);
reactiveTx.flatMap(status -> {
Mono<Object> tx = ...; // put your business logic here
return tx.then(txManager.commit(status))
.onErrorResume(ex -> txManager.rollback(status).then(Mono.error(ex)));
});
val def = DefaultTransactionDefinition()
// explicitly setting the transaction name is something that can be done only programmatically
def.setName("SomeTxName")
def.propagationBehavior = TransactionDefinition.PROPAGATION_REQUIRED
val reactiveTx = txManager.getReactiveTransaction(def)
reactiveTx.flatMap { status ->
val tx = ... // put your business logic here
tx.then(txManager.commit(status))
.onErrorResume { ex -> txManager.rollback(status).then(Mono.error(ex)) }
}