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/

 

posted @ 2019-08-15 11:15  TeyGao  阅读(7361)  评论(0编辑  收藏  举报