Fix/issue import batch rollback #1

Closed
weicw wants to merge 0 commits from fix/issue-2-10-import-batch-rollback into master
Collaborator
No description provided.
weicw added 8 commits 2026-09-25 08:33:21 +08:00
问题:CargoTypeServiceImpl.importCargoType 循环内吞掉异常后正常 return,
方法正常返回导致 Spring 照常提交事务,@Transactional 起不到回滚作用。
含 1 行错误的文件会写入前面若干行正确数据,与「任一行失败即整批零写入」口径不符。

改动:
- ImportFailureException 由 org.springblade.system.excel 迁至
  org.springblade.common.excel(与 ImportFailureExcelUtil 同包)。
  blade-transport 只依赖 blade-system-api,原先拿不到该异常,
  迁到 blade-common 后 blade-system 与 blade-transport 均可引用。
- CargoTypeServiceImpl.importCargoType 补 @Transactional(rollbackFor = Exception.class),
  错误收集完毕后抛 ImportFailureException 触发回滚,不再 return failureList。
- CargoTypeController.importCargoType 由「拿返回值导出」改为
  「catch 异常 → 取 failureList 导出 → return null」,并补上传文件校验,
  对齐 PortTerminalController 的写法。
- PortTerminalController / PortTerminalServiceImpl 仅调整 import 指向新包,行为不变。

验证:
- mvn install -DskipTests 全量编译通过。
- 港口码头回归 45/45 通过,确认「异常搬家」未破坏既有基线。
- 货物类型回归 24/24 通过,含 02_一行错误多行正确_应零写入(库中零写入)。
问题:CommonCargoServiceImpl.importCommonCargo 循环内吞掉异常后正常 return,
方法正常返回导致 Spring 照常提交事务。方法虽有 @Transactional(rollbackFor =
Exception.class),但异常被吞后注解救不了——失败行之前的正确行已经落库。

改动:
- 服务层:错误收集完毕后若 failureList 非空,抛 ImportFailureException
  (org.springblade.common.excel,#2 已迁入 blade-common)触发整批回滚。
- 修复失败明细原因为空的问题:catch 里除写入 failureExcel 副本外,
  还必须把原因写回原行对象 excel.setErrorMessage(...)——抛出异常时携带的是
  原表 data,导出工具从行对象的 errorMessage 字段取原因,只写副本会丢。
- 控制器:改为 catch 异常 → 取 failureList 导出 → return null,并补上传
  文件校验,对齐 PortTerminalController 写法。

验证:
- mvn install -DskipTests 全量编译通过。
- 常用货物回归 25/25 通过(新增 tests/fixtures/common-cargo/,
  scripts/api-common-cargo-import-test.sh),含 02_一行错误多行正确_应零写入。
- 港口码头基线回归 45/45 通过,确认无连带影响。
问题:CommonRouteServiceImpl.importCommonRoute 循环内吞掉异常后正常 return,
方法正常返回导致 Spring 照常提交事务。方法虽有 @Transactional(rollbackFor =
Exception.class),但异常被吞后注解救不了——失败行之前的正确行已经落库。

改动:
- 服务层:错误收集完毕后若 failureList 非空,抛 ImportFailureException
  (org.springblade.common.excel)触发整批回滚。catch 里原本就把原因
  写在原行对象上,失败明细原因不丢,无需额外处理。
- 控制器:改为 catch 异常 → 取 failureList 导出(exportFailureReasonOnly)
  → return null,并补上传文件校验,对齐 PortTerminalController 写法。

验证:
- mvn install -DskipTests 全量编译通过。
- 常用线路回归 29/29 通过(新增 tests/fixtures/common-route/,
  scripts/api-common-route-import-test.sh),含 02_一行错误多行正确_应零写入、
  07_与库中线路重名(基线行不受回滚影响)。
- 港口码头 45/45、常用货物 25/25 基线回归通过,确认无连带影响。
问题:CurrencyServiceImpl.importCurrency 无 @Transactional,循环内吞掉异常
后正常 return,失败行之前的正确行已落库。且循环内除 save 外还有
rebuildEnabledValidity 派生写(按 code 重算启用记录有效期区间),
若只回滚主表遗漏派生写,会留下「主表回滚了、有效期却按失败批次算过」的脏数据。

改动:
- 服务层:补 @Transactional(rollbackFor = Exception.class),错误收集完后
  抛 ImportFailureException(org.springblade.common.excel),
  主表 save 与派生写 rebuildEnabledValidity 在同一事务内一起回滚。
- CurrencyExcel.errorMessage 由 @ExcelProperty 改为 @ExcelIgnore:
  原先导出模板会多出 errorMessage 空列(与 issue #12 运单模板同款问题)。
- 控制器:改 catch 异常导出 + 补上传文件校验,对齐 PortTerminal 写法。

验证:mvn install -DskipTests 通过;币种回归 25/25(含派生区间
正确性断言与零写入断言);同批修复顺带覆盖 issue #12 同类问题。
问题:FeeItemServiceImpl.importFeeItem 虽有 @Transactional,但循环内吞掉
异常后正常 return,Spring 照常提交——失败行之前的正确行已落库。

改动:
- 服务层:错误收集完后抛 ImportFailureException(org.springblade.common.excel)
  触发整批回滚;同时把失败原因写回原行对象 excel.setErrorMessage——
  抛出异常时携带的是原表 data,导出工具从行对象的 errorMessage 字段取原因,
  只写在 FeeItemImportFailureExcel 副本上会导致失败明细原因为空。
- 控制器:改 catch 异常导出(exportFailureReasonOnly)+ 补上传文件校验,
  对齐 PortTerminalController 写法。

验证:mvn install -DskipTests 通过;费用项回归 20/20
(tests/fixtures/fee-item/,含 02_一行错误多行正确_应零写入)。
问题:CreditScoreQuantificationServiceImpl.importCreditScoreQuantification
循环单位是「评定表名称」分组(每分组一次 submit,写主表+项目+选项等多表),
异常被 catch 吞掉后正常 return,Spring 照常提交——失败分组之前的
正确分组已经落库。

改动:
- 服务层:任一分组失败、errorList 非空时抛 ImportFailureException
  (org.springblade.common.excel)触发整批回滚,失败分组之前已 submit
  的正确分组一起退掉。失败明细粒度保留既有行为:覆盖失败分组的全部行。
  「评定表名称」为空的行不走 submit、保持早退标错路径。
- 控制器:改 catch 异常导出(exportFailureReasonOnly)+ 补上传文件校验。

验证:mvn install -DskipTests 通过;评分量化表回归 15/15
(tests/fixtures/credit-score/,含 02_后组失败前组正确_应零写入)。
另确认既有语义:与库中重名的分组走覆盖式更新(saveOrUpdate),非错误。
问题:WaybillServiceImpl.importWaybill 虽有 @Transactional,但循环内吞掉
异常后正常 return,Spring 照常提交——失败行之前的正确行已落库。
本票回滚边界比其它板块宽:submit 虽只写运单主表,但 carrierJson 构造、
多个宽容日期解析都在循环内,失败原因需覆盖;关联表写入在 import-batch
链路,不在本票范围。

改动:
- 服务层:错误收集完后抛 ImportFailureException(org.springblade.common.excel)
  触发整批回滚。catch 里原本就把原因写在原行对象上,无需额外处理。
- 控制器:改 catch 异常导出(exportFailureReasonOnly)+ 补上传文件校验。

验证:mvn install -DskipTests 通过;运单管理回归 19/19
(tests/fixtures/waybill-import/manage-excel/,含 02_一行错误多行正确_应零写入)。
既有 import-batch 链路的 *.json 与 excel/ 用例未改动。
问题:RegionServiceImpl.importRegion 是唯一没有 @Transactional 的导入板块,
循环内吞掉异常后正常 return,已落库行直接提交。且 cacheChanged 标志导致
「先清缓存、再提交事务」:循环内已有行 submit 成功 → 后面行失败 → 方法
正常返回 → 惰性树缓存被清/重算成失败批次的中间状态,库回滚后缓存脏掉。

改动:
- 服务层:补 @Transactional(rollbackFor = Exception.class);错误收集完后
  抛 ImportFailureException(org.springblade.common.excel)触发整批回滚。
- 缓存语义重构:submit 拆出 clearCache 参数(公开 submit(region) 行为不变,
  手工新增仍即时清缓存);导入路径传 false 不逐行清缓存,
  统一移到方法末尾成功路径上——异常抛出后不可达,失败批次缓存保持原状。
- 控制器:改 catch 异常导出(exportFailureReasonOnly)+ 补上传文件校验。

验证:mvn install -DskipTests 通过;行政区划回归 25/25
(tests/fixtures/region/),Redis 断言覆盖:成功路径缓存被清、
失败路径缓存键原样保留、基线行不被失败批次污染。
weicw closed this pull request 2026-09-25 08:34:42 +08:00
b2894lxlx referenced this issue from a commit 2026-10-16 02:02:15 +08:00

Pull request closed

Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: b2894lxlx/tms-erp-api#1