之前出现过一些因为 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) 个码点, 如下图所示:
- Unicode.PNG
- 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;
查看字符集. PNG
查看支持字符序
字符序定义了字符编码的比较规则, 一个字符集对应至少一种字符序(一般是 1 对多), 比如 utf8mb4_unicode_ci 就是 utf8mb4 字符集其中一种字符序
方法 1:SHOW COLLATION;
方法 2:SELECT * FROM information_schema.COLLATIONS;
查看字符序. PNG
怎么预防 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 超集
来源: https://www.qcloud.com/developer/article/1539639