Spring中TransactionSynchronizationManager的使用详解
1 概述
TransactionSynchronizationManager : 事务同步管理器,监听事务的操作,来实现在事务前后可以添加一些指定操作
在遇到一些场景, 如上一步保存的数据, 在接下来的异步处理的业务中有使用,但是因为保存数据过程中,可能出现异常,导致数据回滚,那么后续的业务操作也需要放弃. 对于上述业务场景, 可以使用TransactionSynchronizationManager解决问题
查看一下 TransactionSynchronizationManager 类 :
public abstract class TransactionSynchronizationManager { private static final Log logger = LogFactory.getLog(TransactionSynchronizationManager.class); private static final ThreadLocal<Map<Object, Object>> resources = new NamedThreadLocal<>("Transactional resources"); private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations = new NamedThreadLocal<>("Transaction synchronizations"); private static final ThreadLocal<String> currentTransactionName = new NamedThreadLocal<>("Current transaction name"); private static final ThreadLocal<Boolean> currentTransactionReadOnly = new NamedThreadLocal<>("Current transaction read-only status"); private static final ThreadLocal<Integer> currentTransactionIsolationLevel = new NamedThreadLocal<>("Current transaction isolation level"); private static final ThreadLocal<Boolean> actualTransactionActive = new NamedThreadLocal<>("Actual transaction active"); // ... }
参数说明:
- resources 保存连接资源, 一个方法里面可能包含两个事务(比如事务传播特性为:TransactionDefinition#PROPAGATION_REQUIRES_NEW),所以就用 Map 来保存资源.
- synchronizations 线程同步器,对 Spring 事务的扩展. 在Spring中通过@Transactional注解,在方法上,这个方法就有事务特性.
- currentTransactionReadOnly 保存当前事务是否只读
- currentTransactionName 保存当前事务名称,默认为空
- currentTransactionIsolationLevel 保存当前事务的隔离级别
- actualTransactionActive 保存当前事务是否还处于Active活跃状态
2 案例
以常见的用户注册,然后发送激活码为例.
public void save(){ // 保存用户 saveUser(); // 发送消息 异步执行 executorService.execute(() -> sendMessage()); }
说明:
在用户注册操作, 会将用户信息报错,可能会调一些其他模块,如积分模块等等, 进行数据库报错操作.会进行数据回滚, 但是异步操作,此时不能再进行回滚了.
所以我们需要等保存数据的事务,已经完成提交,再执行异步操作.
改造:
public void save(){ // 保存用户 saveUser(); // 判断当前线程是否存在活跃状态的事务 boolean actualTransactionActive = TransactionSynchronizationManager.isActualTransactionActive(); // 不存在则事务都完成 if (!actualTransactionActive){ // 异步操作 发送消息 executorService.execute(() -> sendMessage()); }else{ // 存在活跃事务, 则监听事务, afterCommit是指事务提交完再执行 TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() { @Override public void afterCommit() { // 异步操作 发送消息 executorService.execute(() -> sendMessage()); } }); } }
通过TransactionSynchronizationManager,保证当前线程的事务都提交完成后,再进行异步的消息发送,解决了上述的问题. 避免出现数据未保存,而发送激活码或提示信息等.
查看一下 TransactionSynchronizationAdapter 类
public abstract class TransactionSynchronizationAdapter implements TransactionSynchronization, Ordered { @Override public int getOrder() { return Ordered.LOWEST_PRECEDENCE; } // 暂停此同步 应该从事务同步管理器中解绑资源 @Override public void suspend() { } // 恢复此同步。 应该将资源重新绑定到 TransactionSynchronizationManager @Override public void resume() { } // 将基础会话刷新到数据存储 @Override public void flush() { } // 在事务提交之前调用(在完成之前之前)顺序倒数第四 @Override public void beforeCommit(boolean readOnly) { } // 在事务提交/回滚之前调用。顺序倒数第三 @Override public void beforeCompletion() { } // 在事务提交后调用 顺序倒数第二 @Override public void afterCommit() { } // 在事务提交/回滚后调用 可以进行资源清理 顺序倒数第一 @Override public void afterCompletion(int status) { } }
根据上述类方法含义,通常业务选择使用afterCommit进行重写,执行异步业务操作.
3 总结
在上述问题已经场景, 之前有遇到过几次, 都是采用了其他方法解决, 那些方法或多或少都有一些问题,如甚至使用过编程式事务去进行二次控制.而使用TransactionSynchronizationManager, 则是很符合这个业务场景的需求.
到此这篇关于Spring中TransactionSynchronizationManager的使用详解的文章就介绍到这了,更多相关TransactionSynchronizationManager的使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
Springboot中PropertySource的结构与加载过程逐步分析讲解
本文重点讲解一下Spring中@PropertySource注解的使用,PropertySource主要是对属性源的抽象,包含属性源名称name和属性源内容对象source。其方法主要是对这两个字段进行操作2023-01-01
最新评论