这是《Java与MySQL字符集与编码》 第四篇,也是本系列的最后、最想写的一篇。这个系列最初是想了解MySQL的编码问题,在整理的过程中,想到了Java的字节编码问题,所以就产生了这个系列。
1 字符编码与比较规则
字符编码我们前面几节已经做了介绍。这儿只讲一点,MySQL中的阉割UTF-8。
1.1 MySQL中的UTF-8
正常来说,像系统、Java语言本身等各个环节UTF-8都是1~4 字节变长的。而在MySQL中基于效率和容量的考虑,对UTF-8进行了阉割,我们通俗意义上说的MySQL UTF-8是指utf8mb3 (UTF-8 most bytes 3) , 也就是说最大支持3字节。这样就导致了有些可以在其他系统支持的UTF-8字符在MySQL中就不能表示了,比如emoji表情。
为了兼容常规意义上的UTF-8,故MySQL中用utf8mb4 编码方案来支持。 我们看下某个MySQL系统支持哪些字符集:
show charset;

1.2 比较规则
比较规则,就是指比较两个字符的大小。最常用的方式就是使用二进制的比较大小。有些可能会涉及忽略大小写的比较,这就会衍生出了好多的比较规则。每一种编码方案会对应很多的比较规则。 常见的比较规则(以utf-8为例):
show collation like 'utf8%';

2 字符编码与比较规则的设置
MySQL中有4个级别的字符集和比较规则:
服务器级别
数据库级别
表级别
列级别
2.1 服务器级别
SHOW VARIABLES LIKE 'character_set_server';
SHOW VARIABLES LIKE 'collation_server';


当然,我们可以在服务启动时进行设置。
[server]
character_set_server=gbk
collation_server=gbk_chinese_ci
2.2 数据库级别
SHOW VARIABLES LIKE 'character_set_database';
SHOW VARIABLES LIKE 'collation_database';
可以通过如上两个命令来查看。 注意:数据库级别的编码只有在创建时可以指定,创建之后就没有办法修改了。
2.3 表级别
在创建表的时候,可以指定。如果没有指定则使用数据库的编码跟比较规则。

2.4 列级别
一般不会对列进行特殊编码设定,当然如果想设定,可以通过指令修改。比如下面的例子:
ALTER TABLE 表名
[[DEFAULT] CHARACTER SET 字符集名称]
[COLLATE 比较规则名称]
2.5 修改
关于字符编码跟比较规则的修改,遵循如下规则,简单点说二者是联动的:
- 只修改字符集,则比较规则将变为修改后的字符集默认的比较规则。
- 只修改比较规则,则字符集将变为修改后的比较规则对应的字符集。
3 MySQL通信中的字符编码转码
3.1 涉及的流程
在MySQL通信过程中,涉及到从客户端->服务端-> 客户端的整体流程,所以中间会涉及到编码转换的问题。如下图所示(图片来自掘金小册《MySQL 是怎样运行的:从根儿上理解 MySQL》)。

3.2 涉及的配置
MySQL涉及转码的配置有如下几个:
character_set_client
character_set_connection
character_set_results
其中 character_set_client 是决定以什么编码的方式解码客户端传来的编码。 character_set_connection 是 将character_set_client 接收来的字符集转换为具体使用的编码集。 character_set_results 是指结果返回时,给到客户端的编码集。
我们看下数据库的有些相关配置:



3.3 jdbc 编码设置demo
把spring jdbc 的编码改为gbk看下:


UncategorizedSQLException 就是编码的问题了。
那我们再改回到utf-8, 发现就正常了。
4 小结
本文首先讲了MySQL字符编码、比较规则的理论知识,并查看了具体的数据配置。然后又讲了MySQL通信中的字符编码转码的问题。最后我们解答了上一篇文章中,关于jdbc 配置跟character_set_client 的交互问题。
5 参考文献
掘金小册《MySQL 是怎样运行的:从根儿上理解 MySQL》