diff --git a/src/main/java/com/gaotao/modules/warehouse/service/impl/IfsInventoryInitServiceImpl.java b/src/main/java/com/gaotao/modules/warehouse/service/impl/IfsInventoryInitServiceImpl.java index 4e025f00..95b5c043 100644 --- a/src/main/java/com/gaotao/modules/warehouse/service/impl/IfsInventoryInitServiceImpl.java +++ b/src/main/java/com/gaotao/modules/warehouse/service/impl/IfsInventoryInitServiceImpl.java @@ -758,8 +758,8 @@ public class IfsInventoryInitServiceImpl implements IfsInventoryInitService { *

注意:

* * * @param file Excel文件 @@ -953,33 +953,41 @@ public class IfsInventoryInitServiceImpl implements IfsInventoryInitService { int partAttributeSkipped = 0; int partAttributeSaved = 0; + int partAttributeFailed = 0; for (Map rowData : successList) { int rowNumber = (int) rowData.get("rowNumber"); try { - // 1. 插入inventory_stock_ifs表(已存在则抛错) + // 库存写入失败仍整批回滚;料件属性不放在这个 try 里,避免主键冲突中断导入 insertOrUpdateIfsInventory(rowData); + } catch (Exception e) { + log.error("第{}行数据插入失败: {}", rowNumber, e.getMessage(), e); + errorMessages.add("第" + rowNumber + "行: 数据库插入失败 - " + e.getMessage()); + // 前面的行已在同一事务里写入;正常返回会提交,必须显式标记回滚才能一行都不留 + TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + log.warn("=== IFS库存Excel写入失败,已标记整批回滚 === 失败行: {}", rowNumber); + return buildImportAbortResult(errorMessages); + } - // 2. 插入part_attribute表(已存在则跳过,插入异常向上抛出) - PartAttribute partAttribute = (PartAttribute) rowData.get("part_attribute"); - if (partAttribute != null) { + PartAttribute partAttribute = (PartAttribute) rowData.get("part_attribute"); + if (partAttribute != null) { + try { boolean saved = insertPartAttributeIfNotExists(partAttribute); if (saved) { partAttributeSaved++; } else { partAttributeSkipped++; } + } catch (Exception e) { + // 属性失败不能进入错误结果:前端会据此提示“未写入任何数据”,库存事务也不能因此回滚 + partAttributeFailed++; + log.error("第{}行料件属性写入失败,已忽略,不影响库存导入: site={}, partNo={}, 原因: {}", + rowNumber, partAttribute.getSite(), partAttribute.getPartNo(), e.getMessage(), e); } - } catch (Exception e) { - log.error("第{}行数据插入失败: {}", rowNumber, e.getMessage(), e); - errorMessages.add("第" + rowNumber + "行: 数据库插入失败 - " + e.getMessage()); - // 前面的行已在同一事务里写入;正常返回会提交,必须显式标记回滚才能一行都不留 - TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); - log.warn("=== IFS库存Excel写入失败,已标记整批回滚 === 失败行: {}", rowNumber); - return buildImportAbortResult(errorMessages); } } - log.info("=== part_attribute表处理统计 === 新增: {}, 跳过: {}", partAttributeSaved, partAttributeSkipped); + log.info("=== part_attribute表处理统计 === 新增: {}, 跳过: {}, 失败已忽略: {}", + partAttributeSaved, partAttributeSkipped, partAttributeFailed); log.info("=== IFS库存Excel导入完成 === 成功: {}, 失败: 0", successList.size()); Map result = new HashMap<>(); @@ -1037,8 +1045,8 @@ public class IfsInventoryInitServiceImpl implements IfsInventoryInitService { } /** - * 插入part_attribute记录(如果不存在) - * 已存在视为跳过,不报错;插入失败必须抛出,否则库存行会在属性写入失败时被单独提交。 + * 插入part_attribute记录(如果不存在)。 + * 已存在则跳过。插入失败先回滚到保存点再抛出,由调用方记日志后继续,不能把库存导入事务标成回滚。 * * @param partAttribute 料件属性对象 * @return true=成功插入,false=已存在跳过 @@ -1053,7 +1061,24 @@ public class IfsInventoryInitServiceImpl implements IfsInventoryInitService { return false; } - partAttributeMapper.insert(partAttribute); + // SQL Server 主键冲突只中止当前语句,但连接上的事务可能无法再提交。 + // 保存点把失败限制在这次属性插入,回滚后库存导入仍可继续。 + Object savepoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint(); + try { + partAttributeMapper.insert(partAttribute); + } catch (Exception e) { + try { + TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savepoint); + } catch (Exception rollbackEx) { + log.error("料件属性保存点回滚失败: site={}, partNo={}", + partAttribute.getSite(), partAttribute.getPartNo(), rollbackEx); + } + if (e instanceof RuntimeException) { + throw (RuntimeException) e; + } + throw new RuntimeException(e); + } + TransactionAspectSupport.currentTransactionStatus().releaseSavepoint(savepoint); log.debug("料件属性新增成功: site={}, partNo={}", partAttribute.getSite(), partAttribute.getPartNo()); return true;