基于 Spring 事务同步机制的事务后置动作收集器 Starter 实践
基于 Spring 事务同步机制的事务后置动作收集器 Starter 实践一、涉及的技术知识点1.1 Spring 事务同步机制知识点说明TransactionSynchronizationSpring 提供的事务同步回调接口在事务提交/回滚后触发TransactionSynchronizationAdapter适配器类选择性覆写需要的回调方法TransactionSynchronizationManager管理当前线程的事务同步器注册afterCommit()事务提交成功后调用afterCompletion(status)事务完成后调用无论提交还是回滚status 标识结果事务状态常量STATUS_COMMITTED0、STATUS_ROLLED_BACK1、STATUS_UNKNOWN21.2 设计模式模式应用观察者模式收集器作为事务的观察者监听提交/回滚事件命令模式AfterTransactionSyncAction接口封装延迟执行的操作收集器模式在事务内累积多个动作事务结束后批量执行策略模式提交动作和回滚动作分开注册、分开执行1.3 解决的核心问题在Transactional方法内有些操作必须在事务提交后才能执行发 MQ 消息事务未提交就发消息消费者可能查到旧数据释放分布式锁事务未提交就解锁其他线程读到未提交的中间状态调外部接口事务回滚了但外部接口已调用无法撤销缓存更新事务未提交就更新缓存缓存与数据库不一致1.4 Java 核心知识点说明函数式接口AfterTransactionSyncAction只有一个方法支持 LambdaLinkedList保持注册顺序执行方法引用lock::unlock作为AfterTransactionSyncAction传入注博客https://blog.csdn.net/badao_liumang_qizhi二、包结构xxx.xxx.lib.transaction ├── AfterTransactionSyncAction.java // 提交后动作接口 ├── AfterTransactionRollbackSyncAction.java // 回滚后动作接口 └── AfterTransactionActionCollector.java // 核心收集器注册到事务同步器注意无spring.factories不是自动配置库。使用时在业务代码中直接new并注册。三、核心实现流程Transactional 方法内 │ ├─→ new AfterTransactionActionCollector() │ ├─→ collector.addCommitSyncAction(() - sendMqMessage()) // 注册提交后动作 ├─→ collector.addCommitSyncAction(lock::unlock) // 注册释放锁动作 ├─→ collector.addRollbackSyncAction(() - compensate()) // 注册回滚补偿动作 │ ├─→ TransactionSynchronizationManager │ .registerSynchronization(collector) // 注册到Spring事务管理器 │ ├─→ 业务逻辑执行数据库操作等 │ └─→ 事务结束 │ ├── 提交成功 → afterCommit() │ └── 按顺序执行所有 commitActionssendMqMessage() → lock.unlock() │ ├── 回滚 → afterCompletion(STATUS_ROLLED_BACK1) │ └── 按顺序执行所有 rollbackActionscompensate() │ └── afterCompletion() 最终清理 └── commitActions.clear() rollbackActions.clear()四、通用示例代码4.1 AfterTransactionSyncAction提交后动作接口packagecom.example.transaction;/** * 事务提交后执行的动作接口. * 函数式接口支持Lambda表达式. */FunctionalInterfacepublicinterfaceAfterTransactionSyncAction{voidexecute();}4.2 AfterTransactionRollbackSyncAction回滚后动作接口packagecom.example.transaction;/** * 事务回滚后执行的动作接口. * 用于补偿操作如撤销已发的外部通知等. */FunctionalInterfacepublicinterfaceAfterTransactionRollbackSyncAction{voidexecute();}4.3 AfterTransactionActionCollector核心收集器packagecom.example.transaction;importjava.util.LinkedList;importjava.util.List;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.transaction.support.TransactionSynchronizationAdapter;/** * 事务后置动作收集器. * * 在 Transactional 方法内使用收集需要在事务提交/回滚后执行的动作. * * 核心价值 * 1. 保证 MQ 消息在事务提交后才发送消费者能查到已提交数据 * 2. 保证分布式锁在事务提交后才释放其他线程读到一致数据 * 3. 支持事务回滚时执行补偿逻辑 * * 使用方式 * 1. new 一个 collector * 2. addCommitSyncAction() 注册提交后动作 * 3. addRollbackSyncAction() 注册回滚后动作 * 4. TransactionSynchronizationManager.registerSynchronization(collector) 注册 */publicclassAfterTransactionActionCollectorextendsTransactionSynchronizationAdapter{privatestaticfinalintSTATUS_COMMITTED0;privatestaticfinalintSTATUS_ROLLED_BACK1;privatestaticfinalintSTATUS_UNKNOWN2;privatefinalListAfterTransactionSyncActioncommitActionsnewLinkedList();privatefinalListAfterTransactionRollbackSyncActionrollbackActionsnewLinkedList();privatefinalLoggerloggerLoggerFactory.getLogger(getClass());/** * 添加事务提交后执行的动作等同于 addCommitSyncAction. */publicvoidaddSyncAction(AfterTransactionSyncActionaction){logger.debug(add action to thread local: {},action);commitActions.add(action);}/** * 添加事务提交后执行的动作. */publicvoidaddCommitSyncAction(AfterTransactionSyncActionaction){logger.debug(add commit sync action: {},action);commitActions.add(action);}/** * 添加事务回滚后执行的动作. */publicvoidaddRollbackSyncAction(AfterTransactionRollbackSyncActionaction){logger.debug(add rollback sync action: {},action);rollbackActions.add(action);}/** * 事务提交成功后回调. * 按注册顺序依次执行所有 commitActions. */OverridepublicvoidafterCommit(){if(!commitActions.isEmpty()){for(AfterTransactionSyncActionaction:commitActions){logger.debug(begin to execute after commit action: {},action);action.execute();}}else{logger.debug(no commitActions to be executed);}}/** * 事务完成后回调无论提交还是回滚. * 如果是回滚status1执行所有 rollbackActions. * 最后清理所有已注册的动作. */OverridepublicvoidafterCompletion(intstatus){logger.debug(after transaction with status {}, commit action size: {}, rollback action size: {},status,commitActions.size(),rollbackActions.size());if(statusSTATUS_ROLLED_BACK!rollbackActions.isEmpty()){logger.debug(the transaction rolled back! begin to execute roll back actions);for(AfterTransactionRollbackSyncActionaction:rollbackActions){logger.debug(begin to execute after rollback action: {},action);action.execute();}}// 清理防止内存泄漏commitActions.clear();rollbackActions.clear();}}4.4 pom.xmlStarter 侧projectgroupIdcom.example/groupIdartifactIdexample-transaction-action-starter/artifactIdversion1.0.0/versionpackagingjar/packagingdependenciesdependencygroupIdorg.springframework/groupIdartifactIdspring-tx/artifactIdscopeprovided/scope/dependencydependencygroupIdorg.slf4j/groupIdartifactIdslf4j-api/artifactIdscopeprovided/scope/dependency/dependencies/project五、引入方使用5.1 添加依赖dependencygroupIdcom.example/groupIdartifactIdexample-transaction-action-starter/artifactIdversion1.0.0/version/dependency5.2 使用示例1事务提交后发 MQServicepublicclassOrderService{ResourceprivateOrderMqSenderorderMqSender;Transactional(rollbackForException.class)publicvoidcreateOrder(OrderDtoorderDto){// 1. 创建收集器并注册到事务管理器AfterTransactionActionCollectorcollectornewAfterTransactionActionCollector();TransactionSynchronizationManager.registerSynchronization(collector);// 2. 执行数据库操作OrderorderorderRepository.save(convertToEntity(orderDto));// 3. 注册事务提交后发MQLambda 写法collector.addCommitSyncAction(()-{orderMqSender.sendOrderCreatedMessage(order.getId());});// 4. 其他业务逻辑...// 事务提交后MQ消息才会发出如果事务回滚消息不会发}}5.3 使用示例2事务提交后释放分布式锁ServicepublicclassStockService{ResourceprivateDistributedLockProviderdistributedLockProvider;Transactional(rollbackForException.class)publicvoiddeductStock(IntegeritemId,Integerqty){// 1. 获取锁StringlockKeystock_deduct_itemId;DistributedLocklockdistributedLockProvider.getLock(lockKey);lock.tryLock(TimeUnit.MINUTES,1);// 2. 注册事务提交后释放锁AfterTransactionActionCollectorcollectornewAfterTransactionActionCollector();TransactionSynchronizationManager.registerSynchronization(collector);collector.addCommitSyncAction(lock::unlock);// 方法引用// 3. 执行库存扣减stockRepository.deduct(itemId,qty);// 事务提交后锁才释放 → 其他线程读到的一定是已提交的数据// 事务回滚 → afterCompletion 中 clear 动作列表但锁不会主动释放需要等待过期}}5.4 使用示例3提交和回滚分别处理ServicepublicclassPaymentService{Transactional(rollbackForException.class)publicvoidprocessPayment(PaymentDtodto){AfterTransactionActionCollectorcollectornewAfterTransactionActionCollector();TransactionSynchronizationManager.registerSynchronization(collector);// 调用第三方支付已扣款StringpaymentIdthirdPartyPayService.charge(dto.getAmount());// 保存支付记录paymentRepository.save(newPayment(paymentId,dto));// 事务提交后通知下游发货collector.addCommitSyncAction(()-{deliveryService.triggerDelivery(dto.getOrderId());});// 事务回滚后调第三方退款补偿collector.addRollbackSyncAction(()-{thirdPartyPayService.refund(paymentId);});}}5.5 使用示例4结合分布式锁完整场景ServicepublicclassBatchDeliveryService{Transactional(rollbackForException.class)publicvoidbatchConfirmDelivery(DeliveryParamsDtoparams){// 获取锁Stringkeybatch_delivery_params.getMemberId();DistributedLocklockdistributedLockProvider.getLock(key,TimeUnit.MINUTES,10);lock.tryLock(TimeUnit.MINUTES,8);// 注册事务后释放锁AfterTransactionActionCollectorcollectornewAfterTransactionActionCollector();TransactionSynchronizationManager.registerSynchronization(collector);collector.addCommitSyncAction(lock::unlock);// 执行批量发货业务// ... 写入发货单、写入扩展表is_fixed_delivery_date、写出库单 ...// 事务提交后发MQ通知collector.addCommitSyncAction(()-{deliveryMqSender.sendToYc(params.getDeliveryRecordCode());});}}六、关键设计总结设计要点实现方式收益事务与副作用解耦副作用延迟到事务提交后执行MQ 消费者读到已提交数据外部调用不会因回滚而产生脏数据提交/回滚分离commitActions rollbackActions 两个列表不同事务结果执行不同逻辑支持补偿有序执行LinkedList 保持注册顺序多个动作按业务预期顺序执行自动清理afterCompletion 中 clear 两个列表防止内存泄漏零配置无 spring.factories直接 new 使用极简无侵入函数式接口支持 Lambda 和方法引用代码简洁优雅最小依赖仅依赖 spring-tx slf4j任何 Spring 事务项目都能用

相关新闻

SpringBoot中基于 OAuth2 + Spring Security 的用户认证上下文工具库(UC Token Util)Starter 实践

SpringBoot中基于 OAuth2 + Spring Security 的用户认证上下文工具库(UC Token Util)Starter 实践

SpringBoot中基于 OAuth2 Spring Security 的用户认证上下文工具库(UC Token Util)Starter 实践一、涉及的技术知识点 1.1 OAuth2 JWT 认证体系知识点说明OAuth2 协议标准的授权框架,支持 password/client_credentials/refresh_token 等授权…

2026/10/3 16:13:21 阅读更多 →
智能体系统设计模式解析与应用实践

智能体系统设计模式解析与应用实践

1. 智能体设计模式全景概述在当今AI技术快速发展的背景下,智能体(Agent)系统已成为解决复杂问题的关键架构。不同于传统的单次模型调用,智能体系统通过自主决策、多步骤工作流管理和工具使用能力,能够处理更加开放和动态的任务场景。设计模式…

2026/10/5 18:14:28 阅读更多 →
抖音算法突变应对方案:用AI自动化实现流量翻倍的5个关键动作(2024最新版)

抖音算法突变应对方案:用AI自动化实现流量翻倍的5个关键动作(2024最新版)

更多请点击: https://intelliparadigm.com 第一章:抖音算法突变的本质洞察与AI应对范式迁移 抖音算法并非线性演进的静态规则集,而是一个由实时用户反馈、多模态内容理解、跨域行为建模与商业目标动态博弈共同驱动的闭环强化学习系统。近期…

2026/10/5 18:35:12 阅读更多 →

最新新闻

Virtual Mac 安装全流程:从 Dopamine 越狱到 Sileo 部署 macOS 虚拟机

Virtual Mac 安装全流程:从 Dopamine 越狱到 Sileo 部署 macOS 虚拟机

【免费下载链接】VirtualMacOniPad People have dreamed of running macOS on iPad for more than a decade. Today, that dream comes true. With Virtual Mac, iPad finally breaks free from iPadOS, enabling pro apps like Xcode, Terminal, Final Cut Pro, Logic Pro, an…

2026/10/10 14:55:01 阅读更多 →
H3C设备替换实战:IRF堆叠与静态聚合配置指南

H3C设备替换实战:IRF堆叠与静态聚合配置指南

简介:本资源是一份企业级数据中心网络设备升级实施文档,面向网络工程师、系统集成人员及IT运维从业者,聚焦老旧网络设备替换过程中的方案设计、配置迁移与回退保障等核心问题。文档详细记录了用友三号楼数据中心52号与54号机柜的设备替换实践…

2026/10/10 14:55:01 阅读更多 →
SpringBoot小区健身房管理系统毕设:源码、论文与部署全解析

SpringBoot小区健身房管理系统毕设:源码、论文与部署全解析

每年这个时候,后台咨询里最多的就是“SpringBoot毕设怎么做”。尤其是那种“功能不能太简单、页面上要拿得出手、最好能把论文一起带出来”的需求,几乎都指向同一条路线。今天我想认真聊一聊“基于SpringBoot的小区健身房管理系统”这个项目,…

2026/10/10 14:55:01 阅读更多 →
PS5存储扩展与网络优化实战:SSD加装、下载加速与系统维护全攻略

PS5存储扩展与网络优化实战:SSD加装、下载加速与系统维护全攻略

1. 项目概述与核心需求先说结论:AnyPS5 并不是一个官方项目名,而是很多主机玩家和开发者圈子里的"黑话"式统称,指的是一套"把 PS5 玩明白、用透彻"的通用方案集。它不指向某一个具体固件、某一张采集卡或某款加速器&…

2026/10/10 14:55:01 阅读更多 →
主机游戏兼容的工程真相:硬件差异与帧率耦合

主机游戏兼容的工程真相:硬件差异与帧率耦合

每次看到“为什么这台次世代主机不能像玩PS4那样把所有老平台的游戏都完美跑起来”这类讨论,我都能感受到玩家那股真实的热切。作为一个在主机兼容层和模拟器方向折腾过不少年的开发者,我想说一句可能不太顺耳但很实在的话:这事真不是平台方“…

2026/10/10 14:55:01 阅读更多 →
WinSxS文件夹清理指南:用DISM安全释放系统盘空间

WinSxS文件夹清理指南:用DISM安全释放系统盘空间

1. 先搞清楚 WinSxS 到底是个什么东西很多人第一次打开C:\Windows\WinSxS这个文件夹,看到属性里显示十几个 G,甚至二十几个 G,第一反应就是:这玩意儿是不是垃圾?能不能直接删掉腾空间?我当年也是这么想的&a…

2026/10/10 14:54:00 阅读更多 →

日新闻

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

1. 从“卫星轨道分类”这个标题说起:为什么值得花时间搞懂第一次接触“卫星轨道分类”这个概念,很多人会觉得它离自己很远——不就是天上的星星怎么转吗?但如果你正在做航天任务规划、遥感数据接收、星座设计,甚至只是准备一场航天…

2026/10/10 0:00:39 阅读更多 →
Spring AOP 核心原理与实战:从概念到日志切面落地

Spring AOP 核心原理与实战:从概念到日志切面落地

1. 从一个真实痛点说起:为什么你的代码里到处都是重复逻辑刚入行那会儿,我写过一个用户管理模块,注册、登录、改密码、注销四个接口。每个接口里都塞了几乎一样的日志打印、参数校验、事务开启和提交。当时觉得没什么,能跑就行。直…

2026/10/10 0:00:40 阅读更多 →
Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

简介:这是一套面向计算机相关专业学生与项目实战学习者的Python数据采集与分析可视化完整项目,以Boss直聘岗位数据为对象,适合用作毕业设计、课程设计或期末大作业。资源包共38个文件,约246KB,以13个py源码文件为核心&…

2026/10/10 0:00:40 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 11:14:25 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 1:36:08 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 11:14:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 5:23:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 10:38:42 阅读更多 →