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 95b5c043..33bcacda 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 @@ -22,8 +22,11 @@ import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.interceptor.TransactionAspectSupport; +import org.springframework.transaction.support.TransactionTemplate; import lombok.extern.slf4j.Slf4j; import org.springframework.web.multipart.MultipartFile; @@ -60,6 +63,9 @@ public class IfsInventoryInitServiceImpl implements IfsInventoryInitService { @Autowired private PartAttributeMapper partAttributeMapper; + @Autowired + private PlatformTransactionManager transactionManager; + @Override public PageUtils getInventoryStockList(InventoryStock data) { IPage ipage = warehouseMapper.getIfsInventoryStockList( @@ -967,7 +973,11 @@ public class IfsInventoryInitServiceImpl implements IfsInventoryInitService { log.warn("=== IFS库存Excel写入失败,已标记整批回滚 === 失败行: {}", rowNumber); return buildImportAbortResult(errorMessages); } + } + // 全部库存行写入成功后再补充属性,避免后续库存行失败时提前提交属性。 + for (Map rowData : successList) { + int rowNumber = (int) rowData.get("rowNumber"); PartAttribute partAttribute = (PartAttribute) rowData.get("part_attribute"); if (partAttribute != null) { try { @@ -1046,42 +1056,30 @@ public class IfsInventoryInitServiceImpl implements IfsInventoryInitService { /** * 插入part_attribute记录(如果不存在)。 - * 已存在则跳过。插入失败先回滚到保存点再抛出,由调用方记日志后继续,不能把库存导入事务标成回滚。 + * 已存在则跳过。查询与插入使用独立事务,失败仅回滚属性事务,由调用方记日志后继续。 * * @param partAttribute 料件属性对象 * @return true=成功插入,false=已存在跳过 */ private boolean insertPartAttributeIfNotExists(PartAttribute partAttribute) { - PartAttribute existing = partAttributeMapper.getPartAttributeByHeight( - partAttribute.getSite(), partAttribute.getPartNo(), partAttribute.getHeight()); - - if (existing != null) { - log.debug("料件属性已存在,跳过: site={}, partNo={}", - partAttribute.getSite(), partAttribute.getPartNo()); - return false; - } + // JpaTransactionManager 不支持当前 JPA 方言的保存点,不能使用 NESTED/createSavepoint。 + // REQUIRES_NEW 挂起库存事务,确保查询、插入及提交失败都不会污染库存事务。 + TransactionTemplate attributeTransaction = new TransactionTemplate(transactionManager); + attributeTransaction.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + return Boolean.TRUE.equals(attributeTransaction.execute(status -> { + PartAttribute existing = partAttributeMapper.getPartAttributeByHeight( + partAttribute.getSite(), partAttribute.getPartNo(), partAttribute.getHeight()); + if (existing != null) { + log.debug("料件属性已存在,跳过: site={}, partNo={}", + partAttribute.getSite(), partAttribute.getPartNo()); + return false; + } - // 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; + log.debug("料件属性新增成功: site={}, partNo={}", + partAttribute.getSite(), partAttribute.getPartNo()); + return true; + })); } /**