diff --git a/ccdi-project/src/main/resources/mapper/ccdi/project/CcdiBankStatementMapper.xml b/ccdi-project/src/main/resources/mapper/ccdi/project/CcdiBankStatementMapper.xml index 1720917d..f1d8ff69 100644 --- a/ccdi-project/src/main/resources/mapper/ccdi/project/CcdiBankStatementMapper.xml +++ b/ccdi-project/src/main/resources/mapper/ccdi/project/CcdiBankStatementMapper.xml @@ -403,7 +403,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ) on duplicate key update - bank_statement_id = bank_statement_id + batch_id = batch_id diff --git a/ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiBankStatementMapperXmlTest.java b/ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiBankStatementMapperXmlTest.java index d1dd33ae..49539bf1 100644 --- a/ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiBankStatementMapperXmlTest.java +++ b/ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiBankStatementMapperXmlTest.java @@ -132,6 +132,17 @@ class CcdiBankStatementMapperXmlTest { } } + @Test + void insertBatch_shouldAvoidUpdatingAutoIncrementPrimaryKeyInDuplicateBranch() throws Exception { + try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream(RESOURCE)) { + String xml = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8); + + assertTrue(xml.contains("on duplicate key update"), xml); + assertTrue(xml.contains("batch_id = batch_id"), xml); + assertFalse(xml.contains("bank_statement_id = bank_statement_id"), xml); + } + } + private MappedStatement loadMappedStatement(String statementId) throws Exception { Configuration configuration = new Configuration(); configuration.setEnvironment(new Environment("test", new JdbcTransactionFactory(), new NoOpDataSource())); diff --git a/docs/reports/implementation/2026-03-20-bank-statement-mysql1869-fix.md b/docs/reports/implementation/2026-03-20-bank-statement-mysql1869-fix.md new file mode 100644 index 00000000..2fcb2e02 --- /dev/null +++ b/docs/reports/implementation/2026-03-20-bank-statement-mysql1869-fix.md @@ -0,0 +1,54 @@ +# 银行流水批量入库 MySQL 1869 修复记录 + +## 背景 + +文件上传解析完成后,`CcdiFileUploadServiceImpl.fetchAndSaveBankStatements` 调用 +`CcdiBankStatementMapper.insertBatch` 批量写入 `ccdi_bank_statement`。 +线上报错如下: + +- MySQL 错误码:`1869` +- 异常信息:`Auto-increment value in UPDATE conflicts with internally generated values` + +## 根因 + +`ccdi-project/src/main/resources/mapper/ccdi/project/CcdiBankStatementMapper.xml` +中的批量插入 SQL 使用了 no-op upsert: + +```sql +ON DUPLICATE KEY UPDATE + bank_statement_id = bank_statement_id +``` + +`bank_statement_id` 是自增主键。当前 MySQL 版本在 `INSERT ... ON DUPLICATE KEY UPDATE` +场景下,若 duplicate 分支显式更新自增列,即使是自赋值,也会触发 `1869`。 + +## 本次修改 + +1. 将 `insertBatch` 的 duplicate 分支从自增主键自赋值改为普通字段自赋值: + +```sql +ON DUPLICATE KEY UPDATE + batch_id = batch_id +``` + +2. 新增 Mapper XML 回归测试,约束批量去重 SQL 不得再更新自增主键。 + +## 影响说明 + +- 新流水:仍正常插入。 +- 重复流水:仍按唯一键命中后跳过,不改写已有业务数据。 +- 非重复键的其他 SQL 错误:仍然继续抛出,不会被静默吞掉。 + +## 验证 + +执行命令: + +```bash +mvn test -pl ccdi-project -Dtest=CcdiBankStatementMapperXmlTest,CcdiFileUploadServiceImplTest +``` + +重点关注: + +- `insertBatch_shouldAvoidUpdatingAutoIncrementPrimaryKeyInDuplicateBranch` +- `processFileAsync_shouldMarkParsedFailedWhenInsertBatchThrowsUnexpectedSqlError` +