MySQL字符编码与比较规则

510 阅读4分钟

这是《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;

比较重要的就是最大长度(Maxlen) 和 默认比较规则(Default collation)。

1.2 比较规则

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

show collation like 'utf8%';

我们可以看到每种字符集就对应好多的比较规则,不过会有一个默认的比较规则。 其中带有ci 的后缀表示是case ignore,是指不区分大小写。 cs 表示case sensitive ,是指区分大小写。而bin 的后缀则表示是纯二进制的比较。

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》