Spring框架通过使用以下两种方式提供编程式事务管理的方法:
TransactionTemplate
或TransactionalOperator
TransactionManager
直接实现
Spring团队通常建议对命令式流程中的编程式事务管理推荐使用TransactionTemplate
,对响应性代码推荐TransactionalOperator
。第二种方法类似于使用JTA
UserTransaction
API,尽管异常处理的麻烦程度较小。
1.5.1 使用TransactionTemplate
TransactionTemplate
采用与其他Spring模板(如JdbcTemplate
)相同的方法。它使用一种回调方法(使应用程序代码不必进行样板获取和释放事务性资源),并生成意向驱动的代码,因为你的代码仅专注于你要执行的操作。
如下面的示例所示,使用
TransactionTemplate
完全将你与Spring的事务基础结构和api结合在一起。编程式事务管理是否适合你的开发需求是你必须自己做的决定。
必须在事务上下文中运行并且显式使用TransactionTemplate
的应用程序代码类似于下一个示例。作为应用程序开发人员,你可以编写TransactionCallback
实现(通常表示为匿名内部类),其中包含你需要在事务上下文中运行的代码。然后,你可以将自定义TransactionCallback
的实例传递给TransactionTemplate
上暴露的execute(..)
方法。以下示例显示了如何执行此操作:
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();
}
});
}
}
如果没有返回值,则可以将便捷的TransactionCallbackWithoutResult
类与匿名类一起使用,如下所示:
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
updateOperation1();
updateOperation2();
}
});
回调中的代码可以通过在提供的TransactionStatus
对象上调用setRollbackOnly()
方法来回滚事务,如下所示:
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
try {
updateOperation1();
updateOperation2();
} catch (SomeBusinessException ex) {
status.setRollbackOnly();
}
}
});
指定事物配置
你可以通过编程方式或配置方式在TransactionTemplate
上指定事务设置(例如传播模式、隔离级别、超时等)。默认情况下,TransactionTemplate
实例具有默认的事务设置。以下示例显示了针对特定TransactionTemplate
的事务设置的编程自定义:
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...
}
}
以下示例通过使用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
实例。
参考代码:
org.liyong.dataaccess.starter.TransactionTemplateIocContainer
1.5.2 使用TransactionOperator
TransactionOperator
遵循类似于其他响应式操作符的设计。它使用一种回调方法(使应用程序代码不必进行模版获取和释放事务性资源),并生成意向驱动的代码,因为你的代码仅专注于你要执行的操作。
如以下示例所示,使用
TransactionOperator
绝对可以使你与Spring的事务基础结构和API结合。编程式事务管理是否适合你的开发需求是你必须自己做的决定。
必须在事务上下文中运行并且显式使用TransactionOperator
的应用程序代码类似于下一个示例:
public class SimpleService implements Service {
// single TransactionOperator shared amongst all methods in this instance
private final TransactionalOperator transactionalOperator;
// use constructor-injection to supply the ReactiveTransactionManager
public SimpleService(ReactiveTransactionManager transactionManager) {
this.transactionOperator = 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);
}
}
TransactionalOperator
可以通过两种方式使用:
- 使用
Reactor
类型的操作符样式(mono.as(transactionalOperator :: transactional)
) - 其他所有情况的回调样式(
transactionalOperator.execute(TransactionCallback <T>)
)
回调中的代码可以通过在提供的ReactiveTransaction
对象上调用setRollbackOnly()
方法来回滚事务,如下所示:
transactionalOperator.execute(new TransactionCallback<>() {
public Mono<Object> doInTransaction(ReactiveTransaction status) {
return updateOperation1().then(updateOperation2)
.doOnError(SomeBusinessException.class, e -> status.setRollbackOnly());
}
}
});
取消信号
在响应式流中,Subscriber
可以取消其Subscription
并停止其Publisher
。Project Reactor
以及其他库中的操作符,例如next()
、take(long)
、timeout(Duration)
等,都可以发出取消操作。没有办法知道取消的原因,无论是由于错误还是仅仅是出于进一步消费的兴趣,并且在5.2版中,TransactionalOperator
默认在取消时提交事务。在版本5.3中,这种行为将发生改变,事务将在取消时回滚,以创建可靠的和确定性的结果。因此,重要的是要考虑从事务发布服务器下游使用的操作符。特别是在Flux
或其他多值Publisher
的情况下,必须使用完整的输出以允许事务完成。
指定事物配置
你可以为TransactionalOperator
指定事务设置(例如传播模式、隔离级别、超时等)。默认情况下,TransactionalOperator
实例具有默认的事务设置。以下示例显示了针对特定TransactionalOperator
的事务设置的自定义:
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);
}
}
1.5.3 使用TransactionManager
以下各节说明命令式和响应式事务管理器的用法。
使用PlatformTransactionManager
对于命令式事务,可以直接使用org.springframework.transaction.PlatformTransactionManager
来管理事务。为此,通过bean引用将你使用的PlatformTransactionManager
的实现传递给bean。然后,通过使用TransactionDefinition
和TransactionStatus
对象,可以启动事务、回滚和提交。以下示例显示了如何执行此操作:
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);
使用ReactiveTransactionManager
使用响应式事务时,可以直接使用org.springframework.transaction.ReactiveTransactionManager
来管理事务。为此,请通过bean引用将你使用的ReactiveTransactionManager
的实现传递给bean。然后,通过使用TransactionDefinition
和ReactiveTransaction
对象,可以启动事务、回滚和提交。以下示例显示了如何执行此操作:
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)));
});
Spring框架通过使用以下两种方式提供编程式事务管理的方法:
TransactionTemplate
或TransactionalOperator
TransactionManager
直接实现
Spring团队通常建议对命令式流程中的编程式事务管理推荐使用TransactionTemplate
,对响应性代码推荐TransactionalOperator
。第二种方法类似于使用JTA
UserTransaction
API,尽管异常处理的麻烦程度较小。
1.5.1 使用TransactionTemplate
TransactionTemplate
采用与其他Spring模板(如JdbcTemplate
)相同的方法。它使用一种回调方法(使应用程序代码不必进行样板获取和释放事务性资源),并生成意向驱动的代码,因为你的代码仅专注于你要执行的操作。
如下面的示例所示,使用
TransactionTemplate
完全将你与Spring的事务基础结构和api结合在一起。编程式事务管理是否适合你的开发需求是你必须自己做的决定。
必须在事务上下文中运行并且显式使用TransactionTemplate
的应用程序代码类似于下一个示例。作为应用程序开发人员,你可以编写TransactionCallback
实现(通常表示为匿名内部类),其中包含你需要在事务上下文中运行的代码。然后,你可以将自定义TransactionCallback
的实例传递给TransactionTemplate
上暴露的execute(..)
方法。以下示例显示了如何执行此操作:
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();
}
});
}
}
如果没有返回值,则可以将便捷的TransactionCallbackWithoutResult
类与匿名类一起使用,如下所示:
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
updateOperation1();
updateOperation2();
}
});
回调中的代码可以通过在提供的TransactionStatus
对象上调用setRollbackOnly()
方法来回滚事务,如下所示:
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
try {
updateOperation1();
updateOperation2();
} catch (SomeBusinessException ex) {
status.setRollbackOnly();
}
}
});
指定事物配置
你可以通过编程方式或配置方式在TransactionTemplate
上指定事务设置(例如传播模式、隔离级别、超时等)。默认情况下,TransactionTemplate
实例具有默认的事务设置。以下示例显示了针对特定TransactionTemplate
的事务设置的编程自定义:
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...
}
}
以下示例通过使用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
实例。
参考代码:
org.liyong.dataaccess.starter.TransactionTemplateIocContainer
1.5.2 使用TransactionOperator
TransactionOperator
遵循类似于其他响应式操作符的设计。它使用一种回调方法(使应用程序代码不必进行模版获取和释放事务性资源),并生成意向驱动的代码,因为你的代码仅专注于你要执行的操作。
如以下示例所示,使用
TransactionOperator
绝对可以使你与Spring的事务基础结构和API结合。编程式事务管理是否适合你的开发需求是你必须自己做的决定。
必须在事务上下文中运行并且显式使用TransactionOperator
的应用程序代码类似于下一个示例:
public class SimpleService implements Service {
// single TransactionOperator shared amongst all methods in this instance
private final TransactionalOperator transactionalOperator;
// use constructor-injection to supply the ReactiveTransactionManager
public SimpleService(ReactiveTransactionManager transactionManager) {
this.transactionOperator = 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);
}
}
TransactionalOperator
可以通过两种方式使用:
- 使用
Reactor
类型的操作符样式(mono.as(transactionalOperator :: transactional)
) - 其他所有情况的回调样式(
transactionalOperator.execute(TransactionCallback <T>)
)
回调中的代码可以通过在提供的ReactiveTransaction
对象上调用setRollbackOnly()
方法来回滚事务,如下所示:
transactionalOperator.execute(new TransactionCallback<>() {
public Mono<Object> doInTransaction(ReactiveTransaction status) {
return updateOperation1().then(updateOperation2)
.doOnError(SomeBusinessException.class, e -> status.setRollbackOnly());
}
}
});
取消信号
在响应式流中,Subscriber
可以取消其Subscription
并停止其Publisher
。Project Reactor
以及其他库中的操作符,例如next()
、take(long)
、timeout(Duration)
等,都可以发出取消操作。没有办法知道取消的原因,无论是由于错误还是仅仅是出于进一步消费的兴趣,并且在5.2版中,TransactionalOperator
默认在取消时提交事务。在版本5.3中,这种行为将发生改变,事务将在取消时回滚,以创建可靠的和确定性的结果。因此,重要的是要考虑从事务发布服务器下游使用的操作符。特别是在Flux
或其他多值Publisher
的情况下,必须使用完整的输出以允许事务完成。
指定事物配置
你可以为TransactionalOperator
指定事务设置(例如传播模式、隔离级别、超时等)。默认情况下,TransactionalOperator
实例具有默认的事务设置。以下示例显示了针对特定TransactionalOperator
的事务设置的自定义:
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);
}
}
1.5.3 使用TransactionManager
以下各节说明命令式和响应式事务管理器的用法。
使用PlatformTransactionManager
对于命令式事务,可以直接使用org.springframework.transaction.PlatformTransactionManager
来管理事务。为此,通过bean引用将你使用的PlatformTransactionManager
的实现传递给bean。然后,通过使用TransactionDefinition
和TransactionStatus
对象,可以启动事务、回滚和提交。以下示例显示了如何执行此操作:
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);
使用ReactiveTransactionManager
使用响应式事务时,可以直接使用org.springframework.transaction.ReactiveTransactionManager
来管理事务。为此,请通过bean引用将你使用的ReactiveTransactionManager
的实现传递给bean。然后,通过使用TransactionDefinition
和ReactiveTransaction
对象,可以启动事务、回滚和提交。以下示例显示了如何执行此操作:
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)));
});
作者
个人从事金融行业,就职过易极付、思建科技、某网约车平台等重庆一流技术团队,目前就职于某银行负责统一支付系统建设。自身对金融行业有强烈的爱好。同时也实践大数据、数据存储、自动化集成和部署、分布式微服务、响应式编程、人工智能等领域。同时也热衷于技术分享创立公众号和博客站点对知识体系进行分享。
博客地址: http://youngitman.tech