diff --git a/crm-opportunity/src/main/java/com/crm/opportunity/config/SchemeCardOwnerMigrationRunner.java b/crm-opportunity/src/main/java/com/crm/opportunity/config/SchemeCardOwnerMigrationRunner.java index 5b8f70c..8655118 100644 --- a/crm-opportunity/src/main/java/com/crm/opportunity/config/SchemeCardOwnerMigrationRunner.java +++ b/crm-opportunity/src/main/java/com/crm/opportunity/config/SchemeCardOwnerMigrationRunner.java @@ -69,9 +69,12 @@ public class SchemeCardOwnerMigrationRunner implements CommandLineRunner { log.info("[scheme-card-owner-migration] 存量方案卡回填商机归属 {} 行", backfilled); // 放宽旧列为可空:实体已不映射 opp_id,新插卡不带该列——NOT NULL 会让 A3 新建卡 // 首次 INSERT 即失败(真实环境实测)。旧行值保留供审计,新行 NULL。 - jdbcTemplate.execute("ALTER TABLE " + TABLE + " MODIFY COLUMN opp_id bigint NULL" - + " COMMENT '(已废弃·owner 化解耦遗留)历史所属商机ID,新行恒 NULL'"); - log.info("[scheme-card-owner-migration] 旧列 opp_id 已放宽为可空"); + // 仅在列仍 NOT NULL 时执行(幂等:已放宽的库启动零 DDL,避免共享库反复 ALTER) + if (!columnNullable(conn, TABLE, "opp_id")) { + jdbcTemplate.execute("ALTER TABLE " + TABLE + " MODIFY COLUMN opp_id bigint NULL" + + " COMMENT '(已废弃·owner 化解耦遗留)历史所属商机ID,新行恒 NULL'"); + log.info("[scheme-card-owner-migration] 旧列 opp_id 已放宽为可空"); + } } if (!indexExists(conn, TABLE, "uk_osc_owner_customer")) { @@ -99,6 +102,13 @@ public class SchemeCardOwnerMigrationRunner implements CommandLineRunner { } } + private boolean columnNullable(Connection conn, String table, String column) throws SQLException { + DatabaseMetaData meta = conn.getMetaData(); + try (ResultSet rs = meta.getColumns(null, null, table, column)) { + return rs.next() && "YES".equalsIgnoreCase(rs.getString("IS_NULLABLE")); + } + } + private boolean indexExists(Connection conn, String table, String indexName) throws SQLException { DatabaseMetaData meta = conn.getMetaData(); try (ResultSet rs = meta.getIndexInfo(null, null, table, false, false)) {