编码是个大问题
问题描述
1 | create table test_2 |
执行 insert into test (content, mb4) values ('花心', '😍');
出现错误 Incorrect string value: '\xF0\x9F\x98\x8D' for column 'mb4' at row 1
。
问题分析
因为标准的 utf8 字符编码是可以用 1~4 个字节去编码的 21 位字符,这几乎涵盖了能见到的所有字符。然而在 MySQL 的实现中,utf8 即 utf8mb3 最长只能使用 3 个字节,所以只能支持 Unicode 中的大部分字符(U+0000至U+FFFF),但是像一些常见的 emoji (4个字节)就不能存储了,这时候就需要修改字符集为 utf8mb4(注意:utf8mb4 在 MySQL 5.5.3 之后引入)。utf8mb4 是 utf8 的超集,对 utf8 兼容。
问题解决(utf8 转换为 utf8mb4)
1 | -- 修改某个字段的编码集 |
除此之外,还要修改 MySQL 服务器和客户端的连接编码集合。
- character_set_client 客户端发送过来的语句和编码
- character_set_connection mysqld 收到客户端的语句后,要转换到的编码
- character_set_results 指 server 执行语句后,返回给客户端的数据编码
可以使用 SET NAMES 'charset_name' [COLLATE 'collation_name']
代替以下三条语句:
1 | SET character_set_client = charset_name; |
所以可以写成 set names utf8mb4 collate utf8mb4_unicode_ci
。
问题总结
当字段编码从 utf8mb3
转换到 utf8mb4
,只是正常的增删改查并不意味着结束。因为单个字符的字节长度发生变化,需要关注这个变化所带来的影响。
- Key 768 long 错误
对于表行格式是 COMPACT或 REDUNDANT,InnoDB 的索引长度是单个索引的最大字节数,为768。而字段定义的长度是能存储的最大字符数,如 varchar(200)
表示最多能存储 200 个字符。如果字符是 utf8nb3 编码,最大是 600 个字节数,而切换为 utf8mb4,则最大为 800 个字节数,可能导致索引长度溢出。