news 2026/5/5 10:11:53

事务工具类

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
事务工具类

解决的痛点

在数据库事务操作中,经常会出现“事务未按预期生效”的情况。 其中最常见的两类场景是:

  1. 同类内部方法调用导致事务代理未生效
  2. 对事务边界的控制过度依赖 @Transactional 注解

下面举一个在开发中可能会遇到的一个事务失效的场景:

//保存父方法 public void saveParentMethod() { //插入parent StockInfo stockInfo = new StockInfo(); stockInfo.setProductId("parent"); this.stockInfoMapper.insertSelective(stockInfo); //插入child this.saveChildStockInfo(); } //保存子方法 @Transactional(rollbackFor = Exception.class) public void saveChildStockInfo() { StockInfo stockInfo = new StockInfo(); stockInfo.setProductId("child"); this.stockInfoMapper.insertSelective(stockInfo); //制造异常 int i = 1 / 0; }

我们想当然的认为:parent应该入库而child不应该

然而实际情况是:child也入库了。

原因并不是事务失效,而是@Transactional根本没有生效。Spring 的事务是基于代理实现的,同类内部方法调用不会经过代理,因此事务注解不会被触发。

OK,TransactionHelper工具类,就是解决类似的情况,并且可以在一个类中使用private定义的私有方法,同样能进行事务。TransactionHelper 的核心作用是: 让事务控制从「依赖 Spring AOP 代理」转变为「显式、可控的代码级事务边界」。更适合以下场景:

  • 复杂流程编排
  • 同类内部方法调用
  • 希望显式声明事务边界的位置

使用方式

@Component @RequiredArgsConstructor public class YourClass { // 构造注入TransactionHelper private final TransactionHelper transactionHelper; public Result<Void> executeBiz(TaskContext context) { // ... // 事务 transactionHelper.runInTransaction(() -> { // 保存订单 saveOrder(order); // 更新库存数量 updateStore(128); }); return Result.ok(); } // 保存订单 private void saveOrder(Order order) { orderMapper.save(order) } // 更新库存数量 private void updateStore(int count) { storeMapper.updateCount(count); } }

这里TransactionHelper充分利用了JDK8之后的函数式编程特点。把要进行事务的方法,当做参数传入。最终利用spring的PlatformTransactionManager统一控制事务行为。

注意:

runInTransaction 中的代码块不应再嵌套 @Transactional 注解, 否则容易造成事务传播语义混乱。

TransactionHelper庐山真面目

/** * 事务帮助类 * * @author 老马 */ @Slf4j @Component @RequiredArgsConstructor public class TransactionHelper { private final PlatformTransactionManager transactionManager; /** * -1 表示不覆盖 Spring 默认配置 */ public static final int DEFAULT_TIMEOUT = TransactionDefinition.TIMEOUT_DEFAULT; /** * 原事务(REQUIRED) */ public <T> T runInTransaction(Supplier<T> supplier) { return execute(TransactionDefinition.PROPAGATION_REQUIRED, DEFAULT_TIMEOUT, supplier); } public void runInTransaction(Runnable runnable) { runInTransaction(DEFAULT_TIMEOUT, runnable); } public <T> T runInTransaction(int timeout, Supplier<T> supplier) { return execute(TransactionDefinition.PROPAGATION_REQUIRED, timeout, supplier); } public void runInTransaction(int timeout, Runnable runnable) { execute(TransactionDefinition.PROPAGATION_REQUIRED, timeout, () -> { runnable.run(); return null; }); } /** * 新事务(REQUIRES_NEW) */ public <T> T runInNewTransaction(Supplier<T> supplier) { return execute(TransactionDefinition.PROPAGATION_REQUIRES_NEW, DEFAULT_TIMEOUT, supplier); } public void runInNewTransaction(Runnable runnable) { runInNewTransaction(DEFAULT_TIMEOUT, runnable); } public <T> T runInNewTransaction(int timeout, Supplier<T> supplier) { return execute(TransactionDefinition.PROPAGATION_REQUIRES_NEW, timeout, supplier); } public void runInNewTransaction(int timeout, Runnable runnable) { execute(TransactionDefinition.PROPAGATION_REQUIRES_NEW, timeout, () -> { runnable.run(); return null; }); } /** * 通用事务执行逻辑 */ private <T> T execute(int propagation, int timeout, Supplier<T> supplier) { TransactionTemplate template = buildTemplate(propagation, timeout); return template.execute(status -> { try { return supplier.get(); } catch (RuntimeException e) { status.setRollbackOnly(); log.error("事务回滚:propagation={}, timeout={}", propagation, timeout, e); throw e; } catch (Exception e) { status.setRollbackOnly(); log.error("事务回滚:propagation={}, timeout={}", propagation, timeout, e); throw new RuntimeException(e); } catch (Throwable t) { status.setRollbackOnly(); log.error("事务回滚:propagation={}, timeout={}", propagation, timeout, t); throw t; } }); } /** * 构建事务模板 */ private TransactionTemplate buildTemplate(int propagation, int timeout) { TransactionTemplate template = new TransactionTemplate(transactionManager); template.setPropagationBehavior(propagation); // timeout = -1 表示使用 Spring 默认配置 if (timeout != DEFAULT_TIMEOUT) { template.setTimeout(timeout); } return template; } }

补充说明:

  1. 为确保 Error / 非 RuntimeException 场景下事务同样回滚, execute 方法中统一捕获 Throwable 并显式标记 rollbackOnly。
  2. TransactionHelper不会吞异常, 异常会继续向上抛出,由上层统一处理, 以避免出现“事务回滚但业务误以为成功”的问题。

使用中特别注意

⚠ 特别注意(强约束):

TransactionHelper 基于 Spring 本地事务(PlatformTransactionManager),因此仅对【单一数据源】生效。如下代码是有效的:

@DS(TableNameConstant.DATABASE_NAME_RTPAY) public void testTransaction() { transactionHelper.runInTransaction(() -> { bizServiceHelpler.insertMerchant(); bizServiceHelpler.insertCity(); }); }

在 DS 多数据源场景下:

  • 同一个事务中禁止切换数据源
  • 不同数据源之间无法实现原子回滚

如果业务需要跨数据源事务控制,请使用 DS 框架提供的 @DSTransactional,或明确拆分为多个独立事务处理。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/19 22:39:43

基于matlab的bp网络车牌识别系统

- 标题&#xff1a; 基于matlab的bp网络车牌识别系统 - 关键词&#xff1a; matlab GUI界面 数字图像预处理 定位车牌 字符分割 bp神经网络识别 - 步骤: 打开图像 灰度化 阈值化 边缘检测 孔洞填充 形态学操作 滤波操作 粗定位 精定位 字符分割 bp神经网络识别 - 简述: 使用mat…

作者头像 李华
网站建设 2026/4/21 15:52:10

基于Springboot的社区共享充电宝租赁管理系统

社区共享充电宝租赁管理系统课题背景随着移动互联网的快速发展和智能终端的普及&#xff0c;手机、平板等电子设备已成为人们日常生活中不可或缺的工具。然而&#xff0c;电池续航问题始终是制约用户体验的关键因素之一。在公共场所&#xff0c;用户常常面临设备电量不足的困扰…

作者头像 李华
网站建设 2026/5/3 10:12:04

App测试时常用的adb命令

adb 全称为 Android Debug Bridge&#xff08;Android 调试桥&#xff09;&#xff0c;是 Android SDK 中提供的用于管理 Android 模拟器或真机的工具。 adb 是一种功能强大的命令行工具&#xff0c;可让 PC 端与 Android 设备进行通信。adb 命令可执行各种设备操作&#xff0…

作者头像 李华
网站建设 2026/4/18 7:53:41

必看!青年拔尖人才支持计划项目优化申报策略与重要注意事项

一、青年拔尖人才支持计划项目优化申报策略善用多重渠道&#xff1a;除单位推荐外&#xff0c;留意是否开放“专家举荐”或“个人自荐”渠道。主动沟通&#xff1a;与本单位负责推荐的部门&#xff08;如学院科研办、学校人事处&#xff09;保持积极沟通&#xff0c;确保信息同…

作者头像 李华
网站建设 2026/5/3 10:43:15

实邦电子能成为电子产品开发的优质推荐供应商吗?

实邦电子&#xff1a;电子产品开发的优质推荐供应商在竞争激烈的电子产品开发领域&#xff0c;上海实邦电子科技有限公司以其卓越的表现&#xff0c;有足够的实力成为优质推荐供应商。接下来&#xff0c;我们从多个方面来深入了解实邦电子。公司简介&#xff1a;十六载砥砺前行…

作者头像 李华
网站建设 2026/4/24 5:08:07

俄罗斯发动大规模空袭,袭击引发多处火灾!

当地时间21日&#xff0c;乌克兰敖德萨州州长奥列格基佩尔通报称&#xff0c;过去一天&#xff0c;俄罗斯对敖德萨州南部地区的交通、港口和工业基础设施发动大规模空袭。 袭击引发多处火灾&#xff0c;造成财产损失&#xff0c;但未造成人员伤亡。 当天&#xff0c;乌克兰总…

作者头像 李华