MySQL Charset--UTF8和UTF8MB4对比测试
UTF8和UTF8MB4
在早期MySQL版本中,使用只支持最长三字节的UTF8字符集便可以存放所有Unicode字符。随着Unicode的完善,Unicode字符集收录的字符数量越来越多,最新版本的UTF8需要使用1到4个字节来存放Unicode字符,而MySQL为保持版本兼容,依旧使用最多3字节的UTF8字符集,并在MySQL 5.5.3版本引入UTF8MB4字符集来支持4字节的Unicode字符。
汉字 '𤋮' 和 ' 𤋮 ' 是异体字,读音均为xi,但两个字的unicode不同:
𤋮 对应的UNICODE是 \ud850\udeee; 𤋮 对应的UTF8是 ��
𤋮 对应的HEX编码是 %f0%a4%8b%ae
熙 对应的UNICODE是 \u7199
熙 对应的UTF8是 熙
熙 对应的HEX编码是 %e7%86%99
在UTF8字符集模式下测试
创建测试表:
CREATE TABLE `tb5001` ( `ID` INT(11) NOT NULL AUTO_INCREMENT, `C1` VARBINARY(100) DEFAULT NULL, `C2` VARCHAR(100) DEFAULT NULL, PRIMARY KEY (`ID`) ) ENGINE=INNODB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8mb4
在UTF8字符集下测试
SET NAMES utf8; INSERT INTO TB5001(C1,C2) SELECT '𤋮','𤋮';
INSERT INTO TB5001(C1,C2) SELECT '熙','熙'; SELECT * FROM TB5001;
执行第一条INSERT有警告,警告信息为:
Warning Code : 1300 Invalid utf8 character string: 'F0A48B' Warning Code : 1366 Incorrect string value: '\xF0\xA4\x8B\xAE' for column 'C2' at row 1
查询结果为:
在UTF8字符集下,VARCHAR类型"无法支持“四字节的"𤋮",但VARBINARY不受字符集影响。
在UTF8MB4字符集模式下测试
测试脚本
SET NAMES utf8mb4; INSERT INTO TB5001(C1,C2) SELECT '𤋮','𤋮'; INSERT INTO TB5001(C1,C2) SELECT '熙','熙'; SELECT * FROM TB5001;
测试中无任何警告,查询结果:
在UTF8MB4字符集下,VARCHAR类型"完美支持“四字节的"𤋮",但VARBINARY不受字符集影响。
乱码问题
表TB5001字符集已定义为UTF8MB4,表上C1列的字符集也是UTF8MB4,为啥还出现乱码呢?
测试脚本:
SET NAMES utf8; SELECT * FROM TB5001; SET NAMES utf8mb4; SELECT * FROM TB5001;
测试对比图:
虽然表上C1列的字符集是UTF8MB4,能存放4字节的字符,但:
1、对于ID=33的记录,由于在插入时使用UTF8字符集,在插入到C1列前'𤋮'字已经发生乱码,存储到C1列中数据也是乱码,因此无论读取时使用UTF8还是UTF8MB4都是乱码。
2、对于ID-35的记录,由于在插入时使用UTF8MB4字符集,插入C1列前和存储到C1中都正常,在读取时使用UTF8MB4能正常读取,但在读取使用UTF8是乱码。
SET NAMES x相当于执行下面三条语句:
SET character_set_client = x; SET character_set_results = x; SET character_set_connection = x;
要保证数据库正常存储4字节的表情符合生僻字,除将数据库相关表和列设置为UTF8MB4外,还需要确保操作数据库时使用UTF8MB4,需重点关注以下几个方面:
1、数据库启动配置参数
2、应用与数据库连接配置
3、DBA日常运维操作
如DBA操作过程中,使用mysql客户端连接到数据库执行操作,而mysql客户端可能使用默认UTF8字符集(default-character-set),导出乱码问题。
在xshell工具下粘贴下面代码:
SELECT '𤋮','𤋮'; SELECT '熙','熙';
将代码粘贴到vim工具中自动变为:
SELECT '<d850><deee>','<d850><deee>'; SELECT '熙','熙';
将代码粘贴到mysql命令总变为:
因此建议DBA在日常运维中关注生僻字和表情符,避免异常。
参考:http://seanlook.com/2016/10/23/mysql-utf8mb4/