From 0ff9103089db701a18f783ba98cba1d391030239 Mon Sep 17 00:00:00 2001 From: 2995840376 <2995840376@xiaomi.com> Date: Tue, 27 Oct 2026 19:12:13 +0800 Subject: [PATCH] =?UTF-8?q?fix(H):=20=E4=BF=AE=E5=A4=8D=20product=5Fproper?= =?UTF-8?q?ty=20=E9=A9=BC=E5=B3=B0=E9=81=97=E7=95=99=E5=88=97=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E5=90=8E=E5=8F=B0=E4=BA=A7=E5=93=81=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=20500?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题:后台「产品中心 - 产品列表/详情/物模型」报 Unknown column 'completion_mode' in 'field list'(BadSqlGrammarException) 根因:V19(面板 P2 迁移)建列时把 completionMode 直接当作列名写入 product_property(驼峰), 而 MyBatis-Plus 默认把实体字段 completionMode 映射为下划线形式 completion_mode, 实体查询/写入时找不到列。 注:V22 已把 completion_mode 的权威归属判定为 product_action 维度, product_property 上的同名列属于历史兼容,保留但统一为下划线命名。 修复:新增 V23 迁移,将 product_property.completionMode 重命名为 completion_mode - 幂等可重复执行,三种情形分别处理: 1) 仅有驼峰列 -> 直接 RENAME COLUMN 2) 两列都存在 -> 先回填旧列非空值到新列,再 DROP 旧列 3) 仅有下划线列 -> 跳过 - 无存储过程、无 DELIMITER(MySQL batch 管道模式下 DELIMITER 失效) - 全库扫描(COLUMN_NAME <> LOWER(COLUMN_NAME))确认驼峰遗留列仅此一处 上线过程:全库备份 /opt/iotsaas/backup/iot_platform_before_v23.sql -> 克隆库 iot_v23_test 演练两遍(重命名成功 + 幂等无副作用)-> 生产执行 -> 克隆库 DROP 验证:/api/v1/products、/api/v1/products/{id}、/api/v1/products/{id}/spec、 /api/v1/products/{id}/control-schema 全部返回 200,物模型属性正常返回。 --- backend/sql/V23__fix_camelcase_columns.sql | 41 ++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 backend/sql/V23__fix_camelcase_columns.sql diff --git a/backend/sql/V23__fix_camelcase_columns.sql b/backend/sql/V23__fix_camelcase_columns.sql new file mode 100644 index 0000000..5254463 --- /dev/null +++ b/backend/sql/V23__fix_camelcase_columns.sql @@ -0,0 +1,41 @@ +-- ===================================================================== +-- V23 · 修复历史遗留的驼峰列名(后台产品页面 Unknown column 报错) +-- --------------------------------------------------------------------- +-- 背景: +-- V19(面板 P2 迁移)建列时把 completionMode 直接当作列名写入 product_property, +-- 而 MyBatis-Plus 默认把实体字段 completionMode 映射为下划线形式 completion_mode, +-- 于是实体查询/写入时提示 Unknown column 'completion_mode' in 'field list', +-- 后台「产品中心 - 产品详情 / 物模型」接口 500。 +-- 注:V22 已把 completion_mode 的权威归属判定为 product_action 维度, +-- product_property 上的同名列属于历史兼容,保留但统一为下划线命名。 +-- +-- 处理:把 product_property.completionMode 重命名为 completion_mode +-- 幂等,可重复执行;三种情形分别处理 +-- 1) 仅有驼峰列 -> 直接 RENAME +-- 2) 两列都存在 -> 先回填旧列非空值到新列,再删除旧列 +-- 3) 仅有下划线列 -> 无需处理 +-- +-- 无存储过程、无 DELIMITER(MySQL batch 管道模式下 DELIMITER 失效,见 V22 说明)。 +-- ===================================================================== + +SET @has_old = (SELECT COUNT(*) FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='product_property' + AND BINARY COLUMN_NAME = 'completionMode'); +SET @has_new = (SELECT COUNT(*) FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='product_property' + AND BINARY COLUMN_NAME = 'completion_mode'); + +-- 情形 1:只有驼峰列 -> 重命名;情形 2:两列都在 -> 回填旧值(旧列随后单独删除) +SET @ddl = (SELECT IF(@has_old = 0, + 'SELECT 1', + IF(@has_new = 0, + 'ALTER TABLE product_property RENAME COLUMN completionMode TO completion_mode', + 'UPDATE product_property SET completion_mode = completionMode WHERE completion_mode IS NULL AND completionMode IS NOT NULL'))); +PREPARE st FROM @ddl; EXECUTE st; DEALLOCATE PREPARE st; + +-- 情形 2 收尾:删除已回填的驼峰列(情形 1 不触发) +SET @ddl = (SELECT IF(@has_old = 1 AND @has_new = 1, + 'ALTER TABLE product_property DROP COLUMN completionMode', + 'SELECT 1')); +PREPARE st FROM @ddl; EXECUTE st; DEALLOCATE PREPARE st; +