问题分析:什么导致mysql乱码?

2019-11-16 16:48:23 浏览数 (1)

之前出现过一些因为mysql编码使用不正确,导致出现页面乱码的bug,比如utf8不支持Emoji表情等等。这里对乱码问题做下分析,沉淀下来避免再次出现

目录

  1. 先了解3个概念:字符集、编码、乱码
  2. 常见的字符集编码有哪些?
  3. 详解Unicode字符集细节
  4. 怎么查看mysql支持哪些字符集/字符序?
  5. 怎么预防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. 第1次发布GB2312,双字节等宽编码,支持简体汉字字符
  2. 第2次发布GBK,双字节等宽编码,多支持繁体字和生僻字
  3. 第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)个码点,如下图所示:

Unicode.pngUnicode.png
  1. Plane#0 BMP(Basic Multilingual Plane):最重要平面,包含大部分常用字符,比如ASCII,汉字等
  2. Plane#1 SMP:古老的文字,不常用
  3. Plane#2 SIP:BMP中没有包含汉字
  4. Plane#14 SSP:非图形字符

具体Unicode编码表

网上很多工具,这里就不展开,可以等到出现乱码再抠出存储二进制去查一下:

https://www.cnblogs.com/csguo/p/7401874.html

怎么查看mysql支持哪些字符集/字符序

查看支持字符集

方法1:SHOW CHARACTER SET;

方法2:SELECT * FROM information_schema.CHARACTER_SETS;

查看字符集.png查看字符集.png

查看支持字符序

字符序定义了字符编码的比较规则,一个字符集对应至少一种字符序(一般是1对多),比如utf8mb4_unicode_ci就是utf8mb4字符集其中一种字符序

方法1:SHOW COLLATION;

方法2:SELECT * FROM information_schema.COLLATIONS;

查看字符序.png查看字符序.png

怎么预防mysql乱码问题?

查看和mysql编码相关的配置

  1. 查看链接编码 character_set_client、character_set_connection、character_set_results SHOW VARIABLES LIKE '%character%'; 查看链接/服务编码.png查看链接/服务编码.png
  2. 查看mysql服务编码 character_set_server
  3. 查看数据库编码 SELECT * FROM information_schema.SCHEMATA WHERE schema_name="ONLINE_EDU_TEST"; 查看数据库编码.png查看数据库编码.png
  4. 查看表编码 SHOW TABLE STATUS FROM ONLINE_EDU_TEST LIKE 't_online_class_time'; 查看表编码.png查看表编码.png
  5. 查看字段编码(一般看表的编码,某个字段特殊设置比较少) SHOW FULL COLUMNS FROM edu_comment_stored_backup_0; 查看字段编码.png查看字段编码.png

设置和mysql编码相关的配置

  1. 设置链接编码 执行SQL命令:mysql -h xx -P xx -uxx -p --default-character-set='utf8' 调用mysqlclient:sConn.pConn->set_option(new mysqlpp::SetCharsetNameOption("utf8mb4"));
  2. 设置mysql服务编码 启动服务时指定:mysqld --character-set-server=latin1 --collation-server=latin1_swedish_ci 配置文件指定(my.cnf):mysql default-character-set=utf8 运行时修改,但重启失效:SET character_set_server = utf8 ;
  3. 设置数据库编码 创建db:CREATE DATABASE db_name DEFAULT CHARACTER SET charset_name 修改db:ALTER DATABASE db_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
  4. 设置表编码 创建表:CREATE TABLE tbl_name (column_list) DEFAULT CHARACTER SET charset_name 修改表:ALTER TABLE tbl_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
  5. 设置字段编码 创建字段: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乱码的一些实践经验

  1. 保证链接、库、表、字段统一编码方式
  2. 不依赖默认编码,在客户端创建链接和建表的时候,统一显示指定编码。防止迁移DB等场景,因为系统默认编码不同导致乱码
  3. 统一使用utf8_mb4,不用utf8和gbk。因为3个字节utf8只支持unicode的BMP,不支持特殊Unicode编码(补充平面),如Emoji表情;gbk更多在中文环境中使用,较局限。此外: utf8_mb4支持版本:>=mysql5.5.3 utf8_mb4兼容utf8:4个字节utf8_mb4是utf8超集

0 人点赞