fix(push): 删除 push 表中遗留的 app_id 字段

push_device_token 和 push_device_login_log 中存在 NOT NULL 的 app_id 列,
为历史遗留字段(系统已统一使用 appKey),导致 INSERT 时报错 500。
通过 PushSchemaMigrationService 新增迁移删除该字段及对应的旧索引/约束,
并重建 idx_push_device_log_user_time 索引到正确的 app_key 列。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
这个提交包含在:
XuqmGroup 2026-06-26 11:24:36 +08:00
父节点 74028060a8
当前提交 46b437d5c9

查看文件

@ -36,6 +36,7 @@ public class PushSchemaMigrationService {
} }
migrate_v20260527_create_push_operation_log(emit); migrate_v20260527_create_push_operation_log(emit);
migrate_v20260626_remove_app_id(emit);
emit.accept("数据库迁移检查完成"); emit.accept("数据库迁移检查完成");
} }
@ -79,6 +80,23 @@ public class PushSchemaMigrationService {
} }
} }
private boolean columnExists(Connection conn, String table, String column) throws SQLException {
try (ResultSet rs = conn.getMetaData().getColumns(null, null, table, column)) {
return rs.next();
}
}
private boolean indexExists(Connection conn, String table, String indexName) throws SQLException {
try (ResultSet rs = conn.getMetaData().getIndexInfo(null, null, table, false, false)) {
while (rs.next()) {
if (indexName.equalsIgnoreCase(rs.getString("INDEX_NAME"))) {
return true;
}
}
}
return false;
}
// 各版本迁移 // 各版本迁移
private void migrate_v20260527_create_push_operation_log(Consumer<String> emit) { private void migrate_v20260527_create_push_operation_log(Consumer<String> emit) {
@ -110,4 +128,37 @@ public class PushSchemaMigrationService {
log.error("migration {} failed", id, e); log.error("migration {} failed", id, e);
} }
} }
private void migrate_v20260626_remove_app_id(Consumer<String> emit) {
final String id = "v20260626_remove_app_id";
if (migrationApplied(id)) {
emit.accept("[已应用] " + id);
return;
}
try (Connection conn = dataSource.getConnection();
Statement stmt = conn.createStatement()) {
// push_device_token: remove legacy app_id unique key and column
if (columnExists(conn, "push_device_token", "app_id")) {
if (indexExists(conn, "push_device_token", "UKj2xmtmdtxgsohtp9c6exx6vl")) {
stmt.execute("ALTER TABLE push_device_token DROP KEY UKj2xmtmdtxgsohtp9c6exx6vl");
}
stmt.execute("ALTER TABLE push_device_token DROP COLUMN app_id");
}
// push_device_login_log: rebuild index on app_key, remove app_id column
if (columnExists(conn, "push_device_login_log", "app_id")) {
if (indexExists(conn, "push_device_login_log", "idx_push_device_log_user_time")) {
stmt.execute("ALTER TABLE push_device_login_log DROP INDEX idx_push_device_log_user_time");
}
stmt.execute("ALTER TABLE push_device_login_log DROP COLUMN app_id");
if (!indexExists(conn, "push_device_login_log", "idx_push_device_log_user_time")) {
stmt.execute("CREATE INDEX idx_push_device_log_user_time ON push_device_login_log (app_key, user_id, created_at)");
}
}
emit.accept("[已迁移] " + id + ": 删除 push 表中遗留 app_id 字段");
recordMigration(id, "删除 push_device_token 和 push_device_login_log 中遗留的 app_id 字段");
} catch (Exception e) {
emit.accept("[错误] " + id + ": " + e.getMessage());
log.error("migration {} failed", id, e);
}
}
} }