您当前的位置:首页 > 电脑百科 > 数据库 > MYSQL

不得不注意!那些容易被忽视的MySQL字符集问题?

时间:2019-12-05 15:37:25  来源:  作者:

不得不注意!那些容易被忽视的MySQL字符集问题?

 

现象

在使用MySQL客户端书写SQL语句的时候,我们可以在字符串前边加_charset_name的符号,其中的charset_name对应着某个具体的字符集,废话不多说,先写两个例子看一下:

mysql> SELECT _utf8'我';
+-----+
| 我 |
+-----+
| 我 |
+-----+
1 row in set (0.04 sec)

mysql> SELECT _gbk'我';
+-----+
| 鎴 |
+-----+
| 鎴 |
+-----+
1 row in set, 1 warning (0.02 sec)

可以看到第一个查询结果正常,第二个查询出现了乱码。为什么呢?下边细细道来。

原因

我们知道MySQL是一个C/S架构的软件,可以有很多客户端连接到服务器进行交互。客户端发送给服务器的请求以及服务器发送给客户端的响应本质上都是一个二进制的字节串,每当我们从客户端发送一个请求到服务器,服务器处理完成之后再把响应返回给客户端的过程其实发生了很多字符集转换过程。

  • 首先请求会被MySQL客户端编码为字节序列之后通过网络传输到服务器。对于MySQL自带的客户端来说,这个编码过程使用的字符集和我们使用的操作系统的默认字符集是一样的,类Unix系统的默认字符集就是utf8,windows系统的默认字符集就是gbk。
  • 服务器收到字节序列请求之后,会认为该字节串是按照character_set_client系统变量编码的,之后将其从character_set_client转换到character_set_connection,之后进行更深入的处理。
  • 最后再将响应发送到客户端的时候,又会按照character_set_results进行编码。
  • 客户端收到响应字节串之后,按照本客户端规定的字符集进行解码。对于MySQL自带的客户端来说,这个解码过程使用的字符集和我们使用的操作系统的默认字符集是一样的,类Unix系统的默认字符集就是utf8,Windows系统的默认字符集就是gbk。

总结一下这几个涉及到的通信字符集系统变量:

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

现在我的系统中的这几个系统变量的值都是utf8:

mysql> SHOW VARIABLES LIKE 'character_set_client';
+----------------------+-------+
| Variable_name | Value |
+----------------------+-------+
| character_set_client | utf8 |
+----------------------+-------+
1 row in set (0.24 sec)

mysql> SHOW VARIABLES LIKE 'character_set_connection';
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| character_set_connection | utf8 |
+--------------------------+-------+
1 row in set (0.25 sec)

mysql> SHOW VARIABLES LIKE 'character_set_results';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| character_set_results | utf8 |
+-----------------------+-------+
1 row in set (0.30 sec)

如果我们使用了_charset_name前缀,意味着禁止服务器将后续字节从character_set_client转换到character_set_connection,而是默认使用_charset_name代表的字符集作为它后续字节的字符集。比方说:

mysql> SELECT _gbk'我';
+-----+
| 鎴 |
+-----+
| 鎴 |
+-----+
1 row in set, 1 warning (0.02 sec)

我现在使用的是macOS操作系统,所以

  • 客户端发送请求时会将字符'我'按照utf8进行编码,也就是:0xE68891。
  • 服务器收到请求后发现有前缀_gbk,则不会将其后边的字节0xE68891进行从character_set_client到character_set_connection的转换,而是直接把0xE68891认为是某个字符串由gbk编码后得到的字节序列。
  • 然后再把上述0xE68891从gbk转换为character_set_results,也就是utf8。0xE688在gbk中代表汉字'鎴',而0x91无法解码(我们可以看到上述查询结果中有1个warning)。我们紧接着上边的查询语句执行一下SHOW WARNINGS:
mysql> SHOW WARNINGSG
*************************** 1. row ***************************
 Level: Warning
 Code: 1300
Message: Invalid gbk character string: '91'
1 row in set (0.01 sec)

之后将汉字'鎴'再按照utf8进行编码,得到的结果就是E98EB4,把它发送到客户端。

  • 客户端收到之后再解码到屏幕上,解码也使用utf8字符集,所以就出现了鎴。

扩展

如果在我的机器上我执行SELECT LENGTH(_gbk '我')会得到什么结果呢(LENGTH函数用来统计某个字符串共占用多少字节)?有很多小伙伴不经思考,脱口而出:2!哈哈,我们看一下结果验证一下:

mysql> SELECT LENGTH(_gbk '我');
+--------------------+
| LENGTH(_gbk '我') |
+--------------------+
| 3 |
+--------------------+
1 row in set, 1 warning (0.01 sec)

WTH?竟然是3?其实再回想一下我们上边所说的,因为'我'前边加了_gbk,所以不会经历从character_set_client到character_set_connection的转换过程,而是直接把0xE68891当作是一个采用gbk编码的字节串。这个字节串中有3个字节,当然结果就返回3了(虽然0x91这个字节在gbk字符集中是无效的,可以看到上边查询语句中也给出了Warning)。

思考

如果我现在不使用基于macOS操作系统的客户端,而采用基于Windows操作系统的客户端来发送请求,那么下边的语句的返回结果将会是什么呢:

SELECT LENGTH(_utf8 '我');


Tags:MySQL   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
作者:雷文霆 爱可生华东交付服务部 DBA 成员,主要负责Mysql故障处理及相关技术支持。爱好看书,电影。座右铭,每一个不曾起舞的日子,都是对生命的辜负。 本文来源:原创投稿 *爱可生...【详细内容】
2021-12-24  Tags: MySQL  点击:(7)  评论:(0)  加入收藏
一、为什么要搭建主从架构呢1.数据安全,可以进行数据的备份。2.读写分离,大部分的业务系统来说都是读数据多,写数据少,当访问压力过大时,可以把读请求给到从服务器。从而缓解数据...【详细内容】
2021-12-15  Tags: MySQL  点击:(12)  评论:(0)  加入收藏
生成间隙(gap)锁、临键(next-key)锁的前提条件 是在 RR 隔离级别下。有关Mysql记录锁、间隙(gap)锁、临键锁(next-key)锁的一些理论知识之前有写过,详细内容可以看这篇文章...【详细内容】
2021-12-14  Tags: MySQL  点击:(18)  评论:(0)  加入收藏
binlog 基本认识 MySQL的二进制日志可以说是MySQL最重要的日志了,它记录了所有的DDL和DML(除了数据查询语句)语句,以事件形式记录,还包含语句所执行的消耗的时间,MySQL的二...【详细内容】
2021-12-14  Tags: MySQL  点击:(13)  评论:(0)  加入收藏
为查询优化你的查询 大多数的MySQL服务器都开启了查询缓存。这是提高性最有效的方法之一,而且这是被MySQL的数据库引擎处理的。当有很多相同的查询被执行了多次的时候,这些查...【详细内容】
2021-12-09  Tags: MySQL  点击:(15)  评论:(0)  加入收藏
测试的目的和原因,公司有很多程序员,每个程序员对数据库和表结构都有自己的理解。而且每个程序员的理解往往是以效率考虑。既然都是为了效率考虑,那么我就来测试一下究竟哪种使...【详细内容】
2021-12-08  Tags: MySQL  点击:(14)  评论:(0)  加入收藏
当你们考虑项目并发的时候,我在部署环境,当你们在纠结使用ArrayList还是LinkedArrayList的时候,我还是在部署环境。所以啊,技术不止境,我在部环境。今天这篇文章缕一下在同一台服...【详细内容】
2021-12-08  Tags: MySQL  点击:(17)  评论:(0)  加入收藏
对于数据分析来说,MySQL使用最多的是查询,比如对数据进行排序、分组、去重、汇总及字符串匹配等,如果查询的数据涉及多个表,还需要要对表进行连接,本文就来说说MySQL中常用的查询...【详细内容】
2021-12-06  Tags: MySQL  点击:(21)  评论:(0)  加入收藏
在学习SQL语句之前,首先需要区分几个概念,我们常说的数据库是指数据库软件,例如MySQL、Oracle、SQL Server等,而本文提到的数据库是指数据库软件中的一个个用于存储数据的容器。...【详细内容】
2021-11-24  Tags: MySQL  点击:(23)  评论:(0)  加入收藏
概述以前参加过一个库存系统,由于其业务复杂性,搞了很多个应用来支撑。这样的话一份库存数据就有可能同时有多个应用来修改库存数据。比如说,有定时任务域xx.cron,和SystemA域...【详细内容】
2021-11-05  Tags: MySQL  点击:(32)  评论:(0)  加入收藏
▌简易百科推荐
作者:雷文霆 爱可生华东交付服务部 DBA 成员,主要负责Mysql故障处理及相关技术支持。爱好看书,电影。座右铭,每一个不曾起舞的日子,都是对生命的辜负。 本文来源:原创投稿 *爱可生...【详细内容】
2021-12-24  爱可生    Tags:MySQL   点击:(7)  评论:(0)  加入收藏
生成间隙(gap)锁、临键(next-key)锁的前提条件 是在 RR 隔离级别下。有关Mysql记录锁、间隙(gap)锁、临键锁(next-key)锁的一些理论知识之前有写过,详细内容可以看这篇文章...【详细内容】
2021-12-14  python数据分析    Tags:MySQL记录锁   点击:(18)  评论:(0)  加入收藏
binlog 基本认识 MySQL的二进制日志可以说是MySQL最重要的日志了,它记录了所有的DDL和DML(除了数据查询语句)语句,以事件形式记录,还包含语句所执行的消耗的时间,MySQL的二...【详细内容】
2021-12-14  linux上的码农    Tags:mysql   点击:(13)  评论:(0)  加入收藏
为查询优化你的查询 大多数的MySQL服务器都开启了查询缓存。这是提高性最有效的方法之一,而且这是被MySQL的数据库引擎处理的。当有很多相同的查询被执行了多次的时候,这些查...【详细内容】
2021-12-09  元宇宙iwemeta    Tags:mysql   点击:(15)  评论:(0)  加入收藏
测试的目的和原因,公司有很多程序员,每个程序员对数据库和表结构都有自己的理解。而且每个程序员的理解往往是以效率考虑。既然都是为了效率考虑,那么我就来测试一下究竟哪种使...【详细内容】
2021-12-08  吴彬的分享    Tags:Mysql数据库   点击:(14)  评论:(0)  加入收藏
当你们考虑项目并发的时候,我在部署环境,当你们在纠结使用ArrayList还是LinkedArrayList的时候,我还是在部署环境。所以啊,技术不止境,我在部环境。今天这篇文章缕一下在同一台服...【详细内容】
2021-12-08  秃头码哥    Tags:MySQL数据库   点击:(17)  评论:(0)  加入收藏
对于数据分析来说,MySQL使用最多的是查询,比如对数据进行排序、分组、去重、汇总及字符串匹配等,如果查询的数据涉及多个表,还需要要对表进行连接,本文就来说说MySQL中常用的查询...【详细内容】
2021-12-06  笨鸟学数据分析    Tags:MySQL   点击:(21)  评论:(0)  加入收藏
在学习SQL语句之前,首先需要区分几个概念,我们常说的数据库是指数据库软件,例如MySQL、Oracle、SQL Server等,而本文提到的数据库是指数据库软件中的一个个用于存储数据的容器。...【详细内容】
2021-11-24  笨鸟学数据分析    Tags:SQL语句   点击:(23)  评论:(0)  加入收藏
概述以前参加过一个库存系统,由于其业务复杂性,搞了很多个应用来支撑。这样的话一份库存数据就有可能同时有多个应用来修改库存数据。比如说,有定时任务域xx.cron,和SystemA域...【详细内容】
2021-11-05  Java云海    Tags:分布式锁   点击:(32)  评论:(0)  加入收藏
MySQL的进阶查询 一、 按关键字排序 使用ORDERBY语句来实现排序排序可针对一个或多个字段ASC:升序,默认排序方式 【升序是从小到大】DESC:降序 【降序是从大到小】ORDER BY的...【详细内容】
2021-11-05  Java热点    Tags:SQL语句   点击:(28)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条