fix(N): V27 通用回转修复历史遗留的双重编码中文

问题: V26 只按 code 修好了 8 条预设品类, V25 回填的 2210/4120 备注仍是乱码; 全库体检还发现 V22 迁移写入的 platform_type 字典表 8 条名称/备注全部双重编码。

修法: 用 CONVERT(CAST(CONVERT(col USING latin1) AS BINARY) USING utf8mb4) 把 latin1 误解后的字符转回原始字节再按 utf8mb4 重新解释; 仅对 HEX 含 C2xx/C3xx 特征的值生效, 修完不再命中, 因此幂等可重复执行; platform_type 表做存在性判断, 旧结构库也能整段跑完。

验证: 生产 remaining_mojibake=0; 品类接口返回字节为正确 UTF-8(照明=e785a7e6988e); platform_type 涂鸦智能=e6b682e9b8a6e699bae883bd。
This commit is contained in:
2995840376 2026-10-28 08:55:03 +08:00
parent 066d374673
commit 4c8aa5459d

View File

@ -0,0 +1,46 @@
-- =====================================================================
-- V27 · 修复历史遗留的双重编码中文(通用回转)
-- ---------------------------------------------------------------------
-- 现象:后台「品类管理」备注、以及「平台类型」字典的名称/备注显示乱码。
--
-- 成因:V22 / V25 迁移执行时,服务器 mysql 客户端 character_set_client 为 latin1
-- (容器 C locale),UTF-8 字节被按 latin1 解读后再存入 utf8mb4 列
-- → 中文双重编码("涂鸦智能" 变成 C3A6C2B6E2809A...)。
--
-- 治本(已完成,后续迁移不会再犯):
-- - deploy-all.bat 的 mysql 调用已加 --default-character-set=utf8mb4;
-- - V25 / V26 脚本首行已加 SET NAMES utf8mb4。
-- 本脚本负责把历史数据修回来。
--
-- 修法:把 latin1 误解后的字符按 latin1 转回原始字节,再按 utf8mb4 重新解释:
-- CONVERT(CAST(CONVERT(col USING latin1) AS BINARY) USING utf8mb4)
-- 幂等:仅对仍含双重编码特征(HEX 含 C2xx / C3xx)的值生效,修完不再命中。
--
-- 无存储过程、无 DELIMITER;幂等可重复执行。
-- =====================================================================
SET NAMES utf8mb4;
-- ---------- 1) 平台类型字典(V22 写入;表可能不存在,做存在性判断) ----------
SET @has_pt = (SELECT COUNT(*) FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'platform_type');
SET @s = IF(@has_pt > 0,
'UPDATE platform_type
SET name = CONVERT(CAST(CONVERT(name USING latin1) AS BINARY) USING utf8mb4),
remark = CONVERT(CAST(CONVERT(remark USING latin1) AS BINARY) USING utf8mb4),
update_time = NOW()
WHERE deleted = 0
AND (HEX(IFNULL(name, '''')) REGEXP ''C[23][0-9A-F]{2}''
OR HEX(IFNULL(remark, '''')) REGEXP ''C[23][0-9A-F]{2}'')',
'SELECT ''platform_type table not found, skipped'' AS info');
PREPARE stmt FROM @s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- ---------- 2) 品类字典备注(V25 回填历史品类时写入) ----------
UPDATE product_category
SET remark = CONVERT(CAST(CONVERT(remark USING latin1) AS BINARY) USING utf8mb4),
update_time = NOW()
WHERE deleted = 0
AND HEX(IFNULL(remark, '')) REGEXP 'C[23][0-9A-F]{2}';