CHARSET()和COLLATION()仅返回值当前字符集元信息,不转换;CONVERT()静默替换不支持字符为?,CAST()在严格模式下可能报错;LOAD DATA需显式指定CHARACTER SET;ALTER TABLE MODIFY只改元数据,CONVERT TO才重编码。

CHARSET() 和 COLLATION() 函数怎么查当前值
直接用 CHARSET() 和 COLLATION() 可以查字符串或列的字符集与校对规则,但注意它们只作用于「已存在的值」,不反映表定义。比如:
SELECT CHARSET('hello'), COLLATION('hello');返回 utf8mb4 和 utf8mb4_0900_ai_ci(MySQL 8.0 默认),但如果你从一个 latin1 列里 SELECT 出来再套 CHARSET(),结果仍是 latin1 —— 它不会自动转成连接字符集。
常见误判点:以为 CHARSET(expr) 能“修复”乱码。其实它只是告诉你当前 expr 的字符集元信息,不触发任何转换。
CONVERT() 和 CAST() 在跨字符集转换时的区别
CONVERT(expr USING charset) 是显式重解释字节序列,而 CAST(expr AS CHAR CHARACTER SET charset) 语义更接近“按新字符集重新编码”。实际效果常一样,但关键差异在错误处理:
- 若原字符串含目标字符集不支持的字符,
CONVERT(... USING ...)会静默替换成?(取决于 sql_mode) -
CAST(... AS CHAR CHARACTER SET ...)在严格模式下可能报错ERROR 1366 (HY000): Incorrect string value
例如把含 emoji 的 utf8mb4 字符串转成 utf8(即 utf8mb3):
SELECT CONVERT('??' USING utf8); -- 返回 '?',不报错SELECT CAST('??' AS CHAR CHARACTER SET utf8); -- MySQL 5.7+ 通常也转成 '?',但某些配置下会失败
LOAD DATA INFILE 读取 CSV 时中文变问号的根本原因
不是因为表字符集设错了,而是 LOAD DATA INFILE 默认用 character_set_database 解析文件字节 —— 即使你的表是 utf8mb4,如果数据库字符集是 latin1,整行就按 latin1 解码,再存进 utf8mb4 列,结果就是双编码乱码。
必须显式指定:
LOAD DATA INFILE '/tmp/data.csv' INTO TABLE t1 CHARACTER SET utf8mb4;同时确保 CSV 文件本身确实是 UTF-8 编码(无 BOM)。漏掉
CHARACTER SET 子句,等于把解码权交给服务端默认值,非常危险。
ALTER TABLE 修改字符集时为什么数据没变乱,但 LENGTH() 结果变了
执行 ALTER TABLE t1 CONVERT TO CHARACTER SET utf8mb4; 会真正重编码存储内容;而 ALTER TABLE t1 MODIFY c1 VARCHAR(10) CHARACTER SET utf8mb4; 只改元数据,不重编码 —— 如果原来存的是 latin1 字节,现在用 utf8mb4 解释,就会出现每个汉字显示为乱码且 LENGTH(c1) 翻倍(因为 utf8mb4 下一个汉字占 3–4 字节,而 latin1 下占 1 字节)。
安全做法分两步:
ALTER TABLE t1 CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;再验证:
SELECT c1, LENGTH(c1), CHAR_LENGTH(c1) FROM t1 LIMIT 5;若
LENGTH() 明显大于 CHAR_LENGTH()(比如汉字对应 9 或 12),说明已发生多字节膨胀,需回退并检查原始编码。
字符集问题最麻烦的不是看不懂报错,而是“看起来正常但 LENGTH 和 SUBSTRING 行为异常”——这种隐性损坏往往上线后才暴露。










