3.3.2 【MySQL】客户端和服务器通信中的字符集

3.3.2.1 编码和解码使用的字符集不一致的后果

我们知道字符 '我' 在 utf8 字符集编码下的字节串长这样: 0xE68891 ,如果一个程序把这个字节串发送到另一个程序里,另一个程序用不同的字符集去解码这个字节串,假设使用的是 gbk 字符集来解释这串字节,解码过程就是这样的:

  1. 首先看第一个字节 0xE6 ,它的值大于 0x7F (十进制:127),说明是两字节编码,继续读一字节后是0xE688 ,然后从 gbk 编码表中查找字节为 0xE688 对应的字符,发现是字符 '鎴'

  2. 继续读一个字节 0x91 ,它的值也大于 0x7F ,再往后读一个字节发现木有了,所以这是半个字符。

  3. 所以 0xE68891 被 gbk 字符集解释成一个字符 '鎴' 和半个字符。

3.3.2.2 字符集转换的概念

如果接收 0xE68891 这个字节串的程序按照 utf8 字符集进行解码,然后又把它按照 gbk 字符集进行编码,最后编码后的字节串就是 0xCED2 ,我们把这个过程称为 字符集的转换 ,也就是字符串 '我' 从 utf8 字符集转换为gbk 字符集。

3.3.2.3 MySQL中字符集的转换

|--------------------------|-------------------------------------------------------------------|
| 系统变量 | 描述 |
| character_set_client | 服务器解码请求时使用的字符集 |
| character_set_connection | 服务器处理请求时会把请求字符串从 character_set_client 转为 character_set_connection |
| character_set_results | 服务器向客户端返回数据时使用的字符集 |

这几个系统变量在我的计算机上的默认值如下(不同操作系统的默认值可能不同):

大家可以看到这几个系统变量的值都是 utf8 ,为了体现出字符集在请求处理过程中的变化,我们这里特意修改一个系统变量的值:

sql 复制代码
mysql> set character_set_connection = gbk;

从这个分析中我们可以得出这么几点需要注意的地方:

服务器认为客户端发送过来的请求是用 character_set_client 编码的。

假设你的客户端采用的字符集和 character_set_client 不一样的话,这就会出现意想不到的情况。比如我的客户端使用的是 utf8 字符集,如果把系统变量 character_set_client 的值设置为 ascii 的话,服务器可能无法理解我们发送的请求,更别谈处理这个请求了。

服务器将把得到的结果集使用 character_set_results 编码后发送给客户端。

假设你的客户端采用的字符集和 character_set_results 不一样的话,这就可能会出现客户端无法解码结果集的情况,结果就是在你的屏幕上出现乱码。比如我的客户端使用的是 utf8 字符集,如果把系统变量character_set_results 的值设置为 ascii 的话,可能会产生乱码。

character_set_connection 只是服务器在将请求的字节串从 character_set_client 转换为character_set_connection 时使用,它是什么其实没多重要,但是一定要注意,该字符集包含的字符范围一定涵盖请求中的字符,要不然会导致有的字符无法使用 character_set_connection 代表的字符集进行编码。比如你把 character_set_client 设置为 utf8 ,把 character_set_connection 设置成 ascii ,那么此时你如果从客户端发送一个汉字到服务器,那么服务器无法使用 ascii 字符集来编码这个汉字,就会向用户发出一个警告。

我们通常都把 character_set_client 、character_set_connection、character_set_results 这三个系统变量设置成和客户端使用的字符集一致的情况,这样减少了很多无谓的字符集转换。为了方便我们设置, MySQL 提供了一条非常简便的语句:

sql 复制代码
SET NAMES 字符集名;

这一条语句产生的效果和我们执行这3条的效果是一样的:

sql 复制代码
SET character_set_client = 字符集名;
SET character_set_connection = 字符集名;
SET character_set_results = 字符集名;

比方说我的客户端使用的是 utf8 字符集,所以需要把这几个系统变量的值都设置为 utf8 :

sql 复制代码
mysql> SET NAMES utf8;

比方说我的客户端使用的是 utf8 字符集,所以需要把这几个系统变量的值都设置为 utf8 :

另外,如果你想在启动客户端的时候就把 character_set_client 、 character_set_connection 、character_set_results 这三个系统变量的值设置成一样的,那我们可以在启动客户端的时候指定一个叫default-character-set 的启动选项,比如在配置文件里可以这么写:

sql 复制代码
[client]default-character-set=utf8

它起到的效果和执行一遍 SET NAMES utf8 是一样的,都会将那三个系统变量的值设置成 utf8 。

3.3.3 比较规则的应用

比较规则 的作用通常体现比较字符串大小的表达式以及对某个字符串列进行排序中,所以有时候也称为 排序规则 。比方说表 t 的列 col 使用的字符集是 gbk ,使用的比较规则是 gbk_chinese_ci ,我们向里边插入几条记录:

我们查询的时候按照 t 列排序一下:

可以看到在默认的比较规则 gbk_chinese_ci 中是不区分大小写的,我们现在把列 col 的比较规则修改为gbk_bin :

由于 gbk_bin 是直接比较字符的编码,所以是区分大小写的,我们再看一下排序后的查询结果:

相关推荐
山东布谷科技官方几秒前
布谷直播源码部署服务器关于数据库配置的详细说明
运维·服务器·数据库·直播系统源码·直播源码·直播系统搭建·直播软件开发
One_Blanks1 分钟前
渗透测试-Linux基础(1)
linux·运维·安全
yanwushu1 分钟前
Xserver v1.4.2发布,支持自动重载 nginx 配置
mysql·nginx·php·个人开发·composer
爱吃喵的鲤鱼5 分钟前
linux进程的状态之环境变量
linux·运维·服务器·开发语言·c++
dessler17 分钟前
Linux系统-ubuntu系统安装
linux·运维·云计算
向阳121824 分钟前
Dubbo负载均衡
java·运维·负载均衡·dubbo
蓝眸少年CY27 分钟前
MySQL 【流程控制】函数
mysql
荒Huang1 小时前
Linux挖矿病毒(kswapd0进程使cpu爆满)
linux·运维·服务器
海阔天空_20131 小时前
Python pyautogui库:自动化操作的强大工具
运维·开发语言·python·青少年编程·自动化
桥田智能1 小时前
气爪在自动化装配线中是如何应用的?
运维·自动化