往表里插入带中文或 emoji 的数据时报 1366 Incorrect string value,错误里跟着一串十六进制字节。很多人第一反应是连接串没写 charset,但参数改完依然报错,因为问题在表和列的字符集上。

确认到底是哪一层还是旧字符集

SHOW VARIABLES LIKE 'character_set%';

再看目标列:

SELECT COLUMN_NAME, CHARACTER_SET_NAME
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA='你的库名'
  AND TABLE_NAME='你的表名';

列上显示 utf8 或 latin1,就说明建表时用的是旧字符集。MySQL 里的 utf8 实际是 utf8mb3,最多三字节,存不下四字节的 emoji 和部分生僻字。

改表而不是只改连接

ALTER TABLE 你的表名
CONVERT TO CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;

表大的话这条语句会锁表,先在从库或测试环境跑一遍看耗时,业务低峰再执行。动手前先导出结构和数据,字符集转换失败时回滚成本很高,尤其是带外键的表,最好按依赖顺序逐张处理。

连接串也要跟着改

PDO 和常见驱动里写 charset=utf8mb4,注意是 utf8mb4 而不是 utf8。改完再执行一次 SHOW VARIABLES,确认 character_set_client、character_set_connection、character_set_results 三项都是 utf8mb4。

还有一点容易忽略:旧版 MySQL 的索引长度上限是 767 字节,utf8mb4 下单列索引最多建到 191 个字符,直接给较长的 varchar 加唯一索引会失败,需要改前缀长度或升级版本。

作者 9823189

发表回复