之前出现过一些因为mysql编码使用不正确,导致出现页面乱码的bug,比如utf8不支持Emoji表情等等。这里对乱码问题做下分析,沉淀下来避免再次出现
目录
- 先了解3个概念:字符集、编码、乱码
- 常见的字符集编码有哪些?
- 详解Unicode字符集细节
- 怎么查看mysql支持哪些字符集/字符序?
- 怎么预防mysql乱码问题?
先了解3个概念:字符集、编码、乱码
为什么要有字符集编码?
一切都是因为电脑不识字,只认识数字(010101)
故我们需把字符(如'A'这个字符)通过一张字符集表,映射成一个数字ID,编码成2进制存储在电脑内
字符集和编码是两码事
Unicode 是「字符集」
UTF-8 是「编码规则」,是Unicode编码的一种实现
字符集:只规定字符的数字编码,即为每一个「字符」分配唯一的 ID(学名为码位 / 码点 / Code Point)
编码规则:把数字编码转为二进制形式,即将「码位」转换为字节序列的规则(可理解为 加密/解密 的过程)
乱码是怎么产生的?要怎么解决?
写入选择的编码方式,和读取选择的编码方式不一致
故要解决乱码问题,核心思路是让读取的编码方式与写入的一致
常见的字符集编码有哪些?
程序员得掌握哪些字符集编码?
大千世界,语言千万种,字符集编码也非常多,但建议只了解最核心4种就够了,甚至只了解Unicode/UTF-8就够了
英文的终极方案:ASCII
大名鼎鼎的ASCII是最早的美国国家标准,单字节编码,共收录128个字符,统一规定了英文常用符号编码
mysql默认编码:Latin1/ISO 8859-1
单字节编码,字符范围很窄,最多表示字符范围是0-255,应用于英文,不支持中文
中文编码的一波三折:GB2312/GBK
ASCII不支持中文,为了解决中文编码问题,中国国家标准总局发布汉字编码规范,但也是一波三折:
- 第1次发布GB2312,双字节等宽编码,支持简体汉字字符
- 第2次发布GBK,双字节等宽编码,多支持繁体字和生僻字
- 第3次发布GB18030,变长编码,收录了所有Unicode3.1中的字符
最终统一的“万国码”:Unicode/UTF-8
像GBK一样,每个国家搞一套显然全世界是没法统一的。为了彻底解决这个问题,于是Unicode(万国码)诞生了
Unicode记录着世界上所有字符对应的一个数字,仅仅只是一个字符集
为了较好解决Unicode编码问题,UTF-8(1-4字节变长)和UTF-16(2/4字节变长)两种较流行的编码方式诞生了
详解Unicode字符集细节
Code Points
Unicode把每个字符分配的唯一ID叫做码点(Code Points),Unicode共有111万 个码点,现在大概已分配了11万个
Code Space和Code Plane(BMP)
所有码点组成代码空间(Code Space),Unicode把代码空间分成了17个代码平面(Code Plane),编号为#0到#16,每个代码平面包含65536(2^16)个码点,如下图所示:
- Plane#0 BMP(Basic Multilingual Plane):最重要平面,包含大部分常用字符,比如ASCII,汉字等
- Plane#1 SMP:古老的文字,不常用
- Plane#2 SIP:BMP中没有包含汉字
- Plane#14 SSP:非图形字符
具体Unicode编码表
网上很多工具,这里就不展开,可以等到出现乱码再抠出存储二进制去查一下:
https://www.cnblogs.com/csguo/p/7401874.html
怎么查看mysql支持哪些字符集/字符序
查看支持字符集
方法1:SHOW CHARACTER SET;
方法2:SELECT * FROM information_schema.CHARACTER_SETS;
查看支持字符序
字符序定义了字符编码的比较规则,一个字符集对应至少一种字符序(一般是1对多),比如utf8mb4_unicode_ci就是utf8mb4字符集其中一种字符序
方法1:SHOW COLLATION;
方法2:SELECT * FROM information_schema.COLLATIONS;
怎么预防mysql乱码问题?
查看和mysql编码相关的配置
- 查看链接编码 character_set_client、character_set_connection、character_set_results SHOW VARIABLES LIKE '%character%'; 查看链接/服务编码.png
- 查看mysql服务编码 character_set_server
- 查看数据库编码 SELECT * FROM information_schema.SCHEMATA WHERE schema_name="ONLINE_EDU_TEST"; 查看数据库编码.png
- 查看表编码 SHOW TABLE STATUS FROM ONLINE_EDU_TEST LIKE 't_online_class_time'; 查看表编码.png
- 查看字段编码(一般看表的编码,某个字段特殊设置比较少) SHOW FULL COLUMNS FROM edu_comment_stored_backup_0; 查看字段编码.png
设置和mysql编码相关的配置
- 设置链接编码 执行SQL命令:mysql -h xx -P xx -uxx -p --default-character-set='utf8' 调用mysqlclient:sConn.pConn->set_option(new mysqlpp::SetCharsetNameOption("utf8mb4"));
- 设置mysql服务编码 启动服务时指定:mysqld --character-set-server=latin1 --collation-server=latin1_swedish_ci 配置文件指定(my.cnf):mysql default-character-set=utf8 运行时修改,但重启失效:SET character_set_server = utf8 ;
- 设置数据库编码 创建db:CREATE DATABASE db_name DEFAULT CHARACTER SET charset_name 修改db:ALTER DATABASE db_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
- 设置表编码 创建表:CREATE TABLE tbl_name (column_list) DEFAULT CHARACTER SET charset_name 修改表:ALTER TABLE tbl_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
- 设置字段编码 创建字段:ALTER TABLE test_table ADD COLUMN char_column VARCHAR(25) CHARACTER SET utf8; 修改字段:ALTER TABLE test_table CHANGE column_name VARCHAR(25) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
关于mysql乱码的一些实践经验
- 保证链接、库、表、字段统一编码方式
- 不依赖默认编码,在客户端创建链接和建表的时候,统一显示指定编码。防止迁移DB等场景,因为系统默认编码不同导致乱码
- 统一使用utf8_mb4,不用utf8和gbk。因为3个字节utf8只支持unicode的BMP,不支持特殊Unicode编码(补充平面),如Emoji表情;gbk更多在中文环境中使用,较局限。此外: utf8_mb4支持版本:>=mysql5.5.3 utf8_mb4兼容utf8:4个字节utf8_mb4是utf8超集