一台安装了MySQL数据库的电脑
因为这3个系统参数与查询以及结果展示相关,所以我们这里先要创建一张表 t1 : create table t1 (id int not null auto_increment, name varchar(50), age int, primary key(id)) default character set utf8;为了演示方便,我们这里直接设置表的字符集为 utf8,忽略系统变量 character_set_server 和 character_set_database 的影响。然后向表中插入3条记录,为了演示效果,特意让name列的值包含中文字符(方便演示字符集不一致导致查询不到结果和查询结果显示为乱码的情况)!
首先 character_set_client : 这个系统变量表示的是客户端所用的字符集,客户端将SQL语句(DDL或DML)发送给服务端时,这个SQL语句(本质就是一个字符串)需要被编码为字节数组进行发送,那服务端如何知道这里采用的是什么字符集呢?答案就是这个系统变量,服务端获取这个系统变量指定的字符集,并使用这个字符集解码用户发送过来的字节数组!对于windows下通过命令行连接的客户端(我们演示时使用的大黑框窗口),其在将SQL语句发送给服务端时使用gbk字符集对SQL语句进行编码,与之对应的是,该系统变量的值也会被设置为 gbk,两者(编码与解码过程)使用相同的字符集,就不会出现解码错误导致查询不到结果的情况!(图2示例)对于上述示例,我们可以将系统变量 character_set_client 手动变更为utf8字符集,这样我们构造了一个客户端使用字符集和服务端解码字符集不一致的情况,同样执行上述示例中的查询,我们发现这次无法查询到结果!(图3示例)
其次是 character_set_connection, 这个系统变量表示我们的SQL语句在服务端执行过程中使用其指定的字符集进行保存或传递,这个字符集通常不会造成查询不到结果或者显示为乱码的问题,对于 windows系统命令行建立的连接,该系统变量的值同样被设置为 gbk(图示)。如果非要说这个系统变量的影响,我们可以说如果这个系统变量设置的字符集不合理的话,服务端在执行SQL语句过程中,会多产生几次字符编码的转换,从而影响一定的性能!
最后是 character_set_results , 顾名思义,这个系统变量代表SQL执行结果使用的字符集,SQL服务端在执行完SQL语句以后(比如查询),会返回给客户端结果(这些结果本质也是字符串),那这个结果使用什么字符集编码呢? 就是这个系统变量指定的字符集。对于Windows命令行建立的客户端,该系统变量的值同样被默认设置为 gbk,Windows命令行客户端在接收到返回的字节数组后,也会默认使用 gbk 来解码(这个无法变更)并展示给客户,两者使用相同的字符集,不会产生乱码 (图1示)我们同样演示一下,当 character_set_results 指定的字符集和客户端解码使用的字符集不一致的情况,我们手动设置 character_set_results 的值为 utf8, 然后再执行查询,因为服务端返回的结果使用 utf8 字符集编码的字节数据,但命令行客户端却使用 gbk 来进行解码,那结果一目了然,那就是乱码(图2示)
平时我们还会看到有人使用这样的命令格式: set names utf8 (这里是字符集名称,你当然可以指定为其他字符集 比如 gbk), 这个命令是干什么呢? 其他这个命令就是将我们本次连接下的上述三个变量的值全部设置为 utf8(或其他字符集,由你指定),这是一种命令简写的形式(不使用这个命令,我们要设置3个系统变量的值,需要执行3遍 set 命令)!
关于这块,我们来总结一下,看看在一个SQL查询的执行过程中,哪些地方会涉及到字符集转换:1. 客户端使用特定字符集将SQL查询语句编码为字节数据发送到服务端(这部分使用的字符集与特定客户端相关,比如Windows命令行客户端使用的就是 gbk)2. 服务端连接处理模块接收到上述字节数组以后,通过 character_set_client 进行解码,并使用 character_set_connection 指定的字符集编码为字节数组发送给存储引擎,这里如果 character_set_client 和 character_set_connection 两者指定的字符集不一致,则会发生一次字符集转换操作!3. 存储引擎在查询具体表时,如果 character_set_connection 指定的字符集和该表使用的字符集不一致,也会发生一次字符集转换操作!4. 从表中获取到查询结果返回给客户端前,如果表的字符集和 character_set_result 不一致,则还会发生一次字符集转码操作!5. 返回到客户的字节数组,会被按照特定的客户端字符集进行解码,并展示给操作人员。 这些操作中,第1步与最后一步的编码和解码操作,通常与特定的平台和客户端相关,第2、3、4步均与我们这篇经验关联的3个系统变量相关,当你彻底理解了这些编码解码的操作,我相信,MySQL字符集相关的东西是难不住你的。
character_set_client、character_set_connection、character_set_results 3个系统变量均关联特定的连接,在我们新建一个客户端连接(比如通过windows命令行或其他一些数据库工具)时,这3个系统变量通常都会被赋予特定的值