编程式事务管理
Spring框架提供了两种编程式事务管理的方式,分别是:
-
TransactionTemplate
或TransactionalOperator
。 -
直接使用
TransactionManager
实现。
Spring团队通常建议在命令式流程中使用TransactionTemplate
进行编程式事务管理,在响应式代码中使用TransactionalOperator
。第二种方法类似于使用JTA UserTransaction
API,尽管异常处理更加简便。
使用TransactionTemplate
TransactionTemplate
采用与其他Spring模板(如JdbcTemplate
)相同的方法。它使用回调方法(以便使应用程序代码免于执行样板式获取和释放事务资源),从而使代码具有意图驱动性,使您的代码专注于您想要做的事情。
正如接下来的示例所示,使用TransactionTemplate 会将您绝对与Spring的事务基础设施和API耦合在一起。编程式事务管理是否适合您的开发需求是您自己要做出的决定。 |
必须在事务上下文中运行的应用程序代码,并且明确使用TransactionTemplate
的示例类似于下一个示例。作为应用程序开发人员,您可以编写一个TransactionCallback
实现(通常表示为匿名内部类),其中包含您需要在事务上下文中运行的代码。然后,您可以将自定义TransactionCallback
的实例传递给TransactionTemplate
上公开的execute(..)
方法。以下示例显示了如何执行此操作:
-
Java
-
Kotlin
public class SimpleService implements Service {
// 在此实例中所有方法之间共享的单个TransactionTemplate
private final TransactionTemplate transactionTemplate;
// 使用构造函数注入提供PlatformTransactionManager
public SimpleService(PlatformTransactionManager transactionManager) {
this.transactionTemplate = new TransactionTemplate(transactionManager);
}
public Object someServiceMethod() {
return transactionTemplate.execute(new TransactionCallback() {
// 此方法中的代码在事务上下文中运行
public Object doInTransaction(TransactionStatus status) {
updateOperation1();
return resultOfUpdateOperation2();
}
});
}
}
// 使用构造函数注入提供PlatformTransactionManager
class SimpleService(transactionManager: PlatformTransactionManager) : Service {
// 在此实例中所有方法之间共享的单个TransactionTemplate
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()
}
}
})
指定事务设置
您可以在TransactionTemplate
上以编程方式或配置方式指定事务设置(如传播模式、隔离级别、超时等)。默认情况下,TransactionTemplate
实例具有默认事务设置。以下示例显示了为特定TransactionTemplate
程序化定制事务设置:
-
Java
-
Kotlin
public class SimpleService implements Service {
private final TransactionTemplate transactionTemplate;
public SimpleService(PlatformTransactionManager transactionManager) {
this.transactionTemplate = new TransactionTemplate(transactionManager);
// 如果需要,可以在此处显式设置事务设置
this.transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
this.transactionTemplate.setTimeout(30); // 30秒
// 等等...
}
}
class SimpleService(transactionManager: PlatformTransactionManager) : Service {
private val transactionTemplate = TransactionTemplate(transactionManager).apply {
// 如果需要,可以在此处显式设置事务设置
isolationLevel = TransactionDefinition.ISOLATION_READ_UNCOMMITTED
timeout = 30 // 30秒
// 等等...
}
}
以下示例通过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
实例。
使用 TransactionalOperator
TransactionalOperator
遵循类似于其他响应式操作符的操作符设计。它采用回调方法(以便使应用代码免于进行获取和释放事务资源的样板代码),并导致代码是意图驱动的,即您的代码仅关注您想要做的事情。
正如接下来的示例所示,使用 TransactionalOperator 绝对将您与Spring的事务基础设施和API耦合在一起。程序化事务管理是否适合您的开发需求是您自己需要做出的决定。 |
必须在事务上下文中运行的应用程序代码,并且明确使用 TransactionalOperator
的示例如下:
-
Java
-
Kotlin
public class SimpleService implements Service {
// 在此实例中所有方法共享的单个 TransactionalOperator
private final TransactionalOperator transactionalOperator;
// 使用构造函数注入以提供 ReactiveTransactionManager
public SimpleService(ReactiveTransactionManager transactionManager) {
this.transactionalOperator = TransactionalOperator.create(transactionManager);
}
public Mono<Object> someServiceMethod() {
// 此方法中的代码在事务上下文中运行
Mono<Object> update = updateOperation1();
return update.then(resultOfUpdateOperation2).as(transactionalOperator::transactional);
}
}
// 使用构造函数注入以提供 ReactiveTransactionManager
class SimpleService(transactionManager: ReactiveTransactionManager) : Service {
// 在此实例中所有方法共享的单个 TransactionalOperator
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())
}
})
取消信号
在响应式流中,Subscriber
可以取消其 Subscription
并停止其 Publisher
。Project Reactor 中的操作符,以及其他库中的操作符,如 next()
、take(long)
、timeout(Duration)
等,都可以发出取消信号。无法知道取消的原因,无论是由于错误还是仅仅是不再有兴趣继续消费。自版本5.3起,取消信号会导致回滚。因此,重要的是考虑从事务 Publisher
下游使用的操作符。特别是在 Flux
或其他多值 Publisher
的情况下,必须消耗完整的输出以允许事务完成。
指定事务设置
您可以为 TransactionalOperator
指定事务设置(如传播模式、隔离级别、超时等)。默认情况下,TransactionalOperator
实例具有默认事务设置。以下示例展示了为特定 TransactionalOperator
自定义事务设置:
-
Java
-
Kotlin
public class SimpleService implements Service {
private final TransactionalOperator transactionalOperator;
public SimpleService(ReactiveTransactionManager transactionManager) {
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
// 如果需要,可以在此明确设置事务设置
definition.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
definition.setTimeout(30); // 30 秒
// 等等...
this.transactionalOperator = TransactionalOperator.create(transactionManager, definition);
}
}
class SimpleService(transactionManager: ReactiveTransactionManager) : Service {
private val definition = DefaultTransactionDefinition().apply {
// 如果需要,可以在此明确设置事务设置
isolationLevel = TransactionDefinition.ISOLATION_READ_UNCOMMITTED
timeout = 30 // 30 秒
// 等等...
}
private val transactionalOperator = TransactionalOperator(transactionManager, definition)
}
使用TransactionManager
以下各节介绍了命令式和响应式事务管理器的编程用法。
使用PlatformTransactionManager
对于命令式事务,您可以直接使用org.springframework.transaction.PlatformTransactionManager
来管理您的事务。为此,通过一个bean引用将您使用的PlatformTransactionManager
的实现传递给您的bean。然后,通过使用TransactionDefinition
和TransactionStatus
对象,您可以启动事务、回滚和提交。以下示例展示了如何实现:
-
Java
-
Kotlin
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// 明确设置事务名称只能通过编程方式完成
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = txManager.getTransaction(def);
try {
// 在此处放置您的业务逻辑
} catch (MyException ex) {
txManager.rollback(status);
throw ex;
}
txManager.commit(status);
val def = DefaultTransactionDefinition()
// 明确设置事务名称只能通过编程方式完成
def.setName("SomeTxName")
def.propagationBehavior = TransactionDefinition.PROPAGATION_REQUIRED
val status = txManager.getTransaction(def)
try {
// 在此处放置您的业务逻辑
} catch (ex: MyException) {
txManager.rollback(status)
throw ex
}
txManager.commit(status)
使用ReactiveTransactionManager
在使用响应式事务时,您可以直接使用org.springframework.transaction.ReactiveTransactionManager
来管理您的事务。为此,通过一个bean引用将您使用的ReactiveTransactionManager
的实现传递给您的bean。然后,通过使用TransactionDefinition
和ReactiveTransaction
对象,您可以启动事务、回滚和提交。以下示例展示了如何实现:
-
Java
-
Kotlin
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// 明确设置事务名称只能通过编程方式完成
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
Mono<ReactiveTransaction> reactiveTx = txManager.getReactiveTransaction(def);
reactiveTx.flatMap(status -> {
Mono<Object> tx = ...; // 在此处放置您的业务逻辑
return tx.then(txManager.commit(status))
.onErrorResume(ex -> txManager.rollback(status).then(Mono.error(ex)));
});
val def = DefaultTransactionDefinition()
// 明确设置事务名称只能通过编程方式完成
def.setName("SomeTxName")
def.propagationBehavior = TransactionDefinition.PROPAGATION_REQUIRED
val reactiveTx = txManager.getReactiveTransaction(def)
reactiveTx.flatMap { status ->
val tx = ... // 在此处放置您的业务逻辑
tx.then(txManager.commit(status))
.onErrorResume { ex -> txManager.rollback(status).then(Mono.error(ex)) }
}