往表里插入带中文或 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 加唯一索引会失败,需要改前缀长度或升级版本。