对于最新稳定版本,请使用 Spring Framework 7.0.6spring-doc.cadn.net.cn

编程式事务管理

Spring框架提供了两种程序化的事务管理方式,通过使用:spring-doc.cadn.net.cn

Spring 团队通常建议在命令式流程中使用 TransactionTemplate 进行编程式事务管理,在响应式代码中使用 TransactionalOperator。 第二种方法类似于使用 JTA 的 UserTransaction API,尽管其异常处理不那么繁琐。spring-doc.cadn.net.cn

使用TransactionTemplate

TransactionTemplate 采用了与其他 Spring 模板(例如 JdbcTemplate)相同的方式。它使用回调方法(以避免应用程序代码重复编写获取和释放事务资源的样板代码),从而使代码更具意图导向性,即您的代码只需专注于要完成的任务。spring-doc.cadn.net.cn

正如以下示例所示,使用 TransactionTemplate 会将您完全绑定到 Spring 的事务基础设施和 API。编程式事务管理是否适合您的开发需求,需要由您自己做出决定。

必须在事务上下文中运行并显式使用 TransactionTemplate 的应用程序代码类似于下面的示例。作为应用程序开发人员,您可以编写一个 TransactionCallback 实现(通常以匿名内部类的形式表示),其中包含需要在事务上下文中执行的代码。然后,您可以将自定义的 TransactionCallback 实例传递给 execute(..) 所暴露的 TransactionTemplate 方法。以下示例展示了如何实现这一点:spring-doc.cadn.net.cn

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类,并结合匿名类使用,例如如下所示:spring-doc.cadn.net.cn

transactionTemplate.execute(new TransactionCallbackWithoutResult() {
	protected void doInTransactionWithoutResult(TransactionStatus status) {
		updateOperation1();
		updateOperation2();
	}
});
transactionTemplate.execute(object : TransactionCallbackWithoutResult() {
	override fun doInTransactionWithoutResult(status: TransactionStatus) {
		updateOperation1()
		updateOperation2()
	}
})

代码在回调中可以通过调用提供的setRollbackOnly()对象的TransactionStatus方法来回滚事务,如下所示:spring-doc.cadn.net.cn

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: 自定义事务设置:spring-doc.cadn.net.cn

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:spring-doc.cadn.net.cn

<bean id="sharedTransactionTemplate"
		class="org.springframework.transaction.support.TransactionTemplate">
	<property name="isolationLevelName" value="ISOLATION_READ_UNCOMMITTED"/>
	<property name="timeout" value="30"/>
</bean>

您可以将 sharedTransactionTemplate 注入到所需的任意多个服务中。spring-doc.cadn.net.cn

最后,TransactionTemplate 类的实例是线程安全的,因为这些实例不维护任何会话状态。然而,TransactionTemplate 实例确实会维护配置状态。因此,尽管多个类可以共享同一个 TransactionTemplate 实例,但如果某个类需要使用具有不同设置(例如,不同的隔离级别)的 TransactionTemplate,则必须创建两个不同的 TransactionTemplate 实例。spring-doc.cadn.net.cn

使用TransactionalOperator

TransactionalOperator 采用了一种类似于其他响应式操作符的操作符设计。它使用回调方式(使应用程序代码无需编写样板式的事务资源获取与释放逻辑),从而生成意图驱动的代码,即您的代码只需专注于要执行的操作。spring-doc.cadn.net.cn

正如以下示例所示,使用 TransactionalOperator 会将您完全绑定到 Spring 的事务基础设施和 API。编程式事务管理是否适合您的开发需求,需要由您自己做出决定。

必须在事务上下文中运行并且显式使用TransactionalOperator的应用代码类似于以下示例:spring-doc.cadn.net.cn

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 可以用两种方式使用:spring-doc.cadn.net.cn

  • 使用操作符风格的 Project Reactor 类型 (mono.as(transactionalOperator::transactional))spring-doc.cadn.net.cn

  • 回调风格用于其他所有情况(transactionalOperator.execute(TransactionCallback<T>)spring-doc.cadn.net.cn

在回调中的代码可以通过调用提供的setRollbackOnly()对象上的ReactiveTransaction方法来回滚事务,如下所示:spring-doc.cadn.net.cn

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())
	}
})

取消信号

在响应式流(Reactive Streams)中,Subscriber 可以取消其对 Subscription 的订阅并停止其 Publisher。Project Reactor 中的操作符,以及其他库(如 next()take(long)timeout(Duration) 等)中的操作符,都可以发出取消信号。无法得知取消的原因,无论是由于错误还是仅仅因为不再需要消费更多数据。自 5.3 版本起,取消信号会导致事务回滚。因此,必须仔细考虑位于事务 Publisher 下游所使用的操作符。特别是在 Flux 或其他多值 Publisher 的情况下,必须完全消费所有输出,才能使事务顺利完成。spring-doc.cadn.net.cn

指定事务设置

您可以为 TransactionalOperator 指定事务设置(例如传播模式、隔离级别、超时时间等)。默认情况下,TransactionalOperator 实例具有默认的事务设置。以下示例展示了如何为特定的 TransactionalOperator: 自定义事务设置:spring-doc.cadn.net.cn

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)
}

使用TransactionManager

以下部分解释了命令式和响应式事务管理器的程序化使用方法。spring-doc.cadn.net.cn

使用PlatformTransactionManager

对于命令式事务,您可以直接使用 org.springframework.transaction.PlatformTransactionManager 来管理您的事务。为此,请通过 bean 引用将您所使用的 PlatformTransactionManager 实现传递给您的 bean。然后,通过使用 TransactionDefinitionTransactionStatus 对象,您可以启动事务、回滚和提交。以下示例展示了如何实现这一点:spring-doc.cadn.net.cn

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)

使用ReactiveTransactionManager

在使用响应式事务时,您可以直接使用 org.springframework.transaction.ReactiveTransactionManager 来管理您的事务。为此,请通过 Bean 引用将您所使用的 ReactiveTransactionManager 实现传递给您的 Bean。然后,通过使用 TransactionDefinitionReactiveTransaction 对象,您可以启动事务、回滚和提交事务。以下示例展示了如何实现这一点:spring-doc.cadn.net.cn

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)) }
}