配置导入事务问题与修复总结

配置导入事务问题与修复总结

本文档总结配置导入(Excel 模板导入)过程中出现的 UnexpectedRollbackException 与前端错误信息不对的问题、根因及修复方案。


一、问题现象

  1. 后端日志 :org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
  2. 前端展示:页面提示「配置导入失败:Transaction rolled back because it has been marked as rollback-only」,而不是真实的业务错误(如「数据库表不存在:xxx」)
  3. 调试现象 :Sheet1 的 for 循环里已用 try-catch 把异常包进 result,并在 78-79 行正常 return result,但 Controller 仍进入异常捕获分支(110-111 行)

二、根因分析

2.1 事务与"异常即标记回滚"

  • ConfigImportServiceImpl.importFromExcel(InputStream) 使用 @Transactional(rollbackFor = Exception.class),整段导入在一个事务中执行。
  • Spring 行为 :只要在事务内任意时刻 抛出了符合 rollbackFor 的异常,当前事务就会被标记为 rollback-only 。
    标记发生在异常抛出的瞬间,与后续是否在业务代码里 catch 无关。

2.2 Sheet1 场景下的实际流程

  1. Sheet1 的 for 循环中调用 factTableSchemaService.importTableFromDatabase(...)。
  2. 若某张表不存在,FactTableSchemaServiceImpl 抛出 IllegalArgumentException("数据库表不存在:" + tableName)。
  3. 此时 :当前事务(即 importFromExcel 所在事务)被标记为 rollback-only。
  4. 异常随后在 for 循环的 catch 中被捕获,仅执行 result.addError(...),未 rethrow。
  5. 代码继续执行,到 78-79 行 if (!result.isSuccess() && !result.getErrors().isEmpty()) { return result; },正常 return result。
  6. 方法正常返回后,Spring 事务拦截器执行 commit。
  7. 发现事务已是 rollback-only,不允许提交,于是抛出 UnexpectedRollbackException。
  8. 该异常冒泡到 Controller,被 110-111 行 catch (Exception e) 捕获,前端看到的是 commit 失败的消息,而非 result 中已写好的「表xxx导入失败: 数据库表不存在:xxx」。

2.3 两种失败路径对比

场景 执行路径 结果
仅 Sheet1 出错 for 内 catch → 78-79 return result → commit 时抛 UnexpectedRollbackException → Controller 进 catch 前端看到 rollback 提示,result 中正确错误信息未展示
Sheet2/3/5 或字段配置出错 后续某步抛异常 → 外层 catch 后 rethrow → Controller 进 catch 前端看到真实异常信息(修复 rethrow 后)

三、修复方案

3.1 修复一:Sheet1 表导入使用独立事务(REQUIRES_NEW)

目的:让 Sheet1 中单表导入失败时,只回滚该次调用的事务,不污染外层导入事务。

修改 :FactTableSchemaServiceImpl.importTableFromDatabase

  • 原:@Transactional(rollbackFor = Exception.class)
  • 现:@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)

效果:

  • 每次调用 importTableFromDatabase 都会挂起外层事务并开启一个新事务。
  • 某张表导入失败抛异常时,仅该新事务被标记 rollback-only 并回滚。
  • 异常在 Sheet1 的 for 中被 catch 并写入 result,外层 importFromExcel 事务未被标记。
  • 78-79 行 return result 后,外层事务正常 commit,Controller 收到带错误信息的 result,走 success(result),前端可正确展示 result 中的错误列表。

3.2 修复二:外层 catch 不再吞异常(Rethrow)

目的 :当异常来自 Sheet2/3/5 或字段配置等未内部 catch 的步骤时,将真实异常抛出,避免只看到 UnexpectedRollbackException。

修改 :ConfigImportServiceImpl.importFromExcel(InputStream) 最外层 catch

  • 原:catch (Exception e) { ... result.addError(...); result.setSuccess(false); } 后直接 return result。
  • 现:在 catch 末尾增加 throw new RuntimeException(e.getMessage() != null ? e.getMessage() : "配置导入失败", e);。

效果:

  • 后续 Sheet 或字段配置中一旦抛异常,会直接抛出,事务按预期回滚。
  • Controller 的 catch 收到的是包装后的 RuntimeException,getMessage() 为原始业务错误信息,前端可显示「配置导入失败:数据库表不存在:xxx」等真实原因。

四、涉及文件与位置

文件 修改内容
backend/.../FactTableSchemaServiceImpl.java importTableFromDatabase 增加 propagation = Propagation.REQUIRES_NEW,并增加 Propagation 的 import
backend/.../ConfigImportServiceImpl.java 最外层 catch 中在写入 result 后 throw new RuntimeException(..., e)

五、小结

  • 问题本质:事务内抛出的异常会使事务被标记 rollback-only;若异常被业务 catch 且未 rethrow,方法仍会"正常返回",但 commit 时因 rollback-only 再抛 UnexpectedRollbackException,前端只能看到后者。
  • Sheet1 场景 :通过 importTableFromDatabase 使用 REQUIRES_NEW,把单表导入放到独立事务中,表导入失败只回滚该次调用,外层可正常 return result 并 commit,前端拿到 result 中的错误信息。
  • 后续 Sheet 场景:通过外层 catch 后 rethrow,保证真实异常传到 Controller,前端显示真实错误信息。

相关功能说明见:docs/导入模板/配置导入模板说明.md。

相关推荐
彦16 小时前
Excel实用技巧笔记
excel
Logic10118 小时前
Excel流程控制if函数,IF+数组轻松解决复杂判断问题
excel·流程控制·条件判断·if·excel函数·if函数·数组公式
跨境猫小妹1 天前
跨境电商订单导出CSV用Excel打开后订单号变成科学计数法如何定位并修复
excel·跨境电商·营销策略
weixin_440401692 天前
大数据技术-数据分析(EXcel+Python数据处理+SQL)
大数据·python·数据分析·excel
jaysee-sjc2 天前
【苍穹外卖】Day12:工作台数据看板与 Excel 报表导出
java·开发语言·数据库·spring boot·spring·微信·excel
ms365copilot3 天前
Copilot 代理开始进入Word、Excel、PowerPoint,不再只是“问一句答一句”
word·excel·copilot
wuyk5553 天前
PyQt6-第14讲-数据库与Excel双向同步
数据库·python·ui·excel·pyqt
qq_364682153 天前
AI如何将录音内容自动整理成Excel清单
人工智能·excel
Logic1013 天前
Excel信息+照片文件夹,自动合成word格式化文档
word·excel·办公自动化·邮件合并·office技巧·自动插入图片·插入域
Data-Miner4 天前
一个省大模型积分的 Excel 数据处理方案:脱敏生成逻辑,脚本复用把 token 降到 0
人工智能·windows·excel