mysql传输编码配置_MySQL的字符编码体系(二)——传输数据编码

MySQL的字符编码体系能够分成两部分:一部分是关于数据库server本身存储数据表时怎样管理字符数据的编码;还有一部分是关于client与数据库server数据传输怎样编码。上一篇MySQL的字符编码体系(一)——数据存储编码讨论了数据存储编码,本篇讨论数据传输编码。

MySQL的client能够分为两种:一种就是用C语言写的官方client——MySQL命令程序;一种就是寻常程序猿使用JDBC等connector API写成的client。这里仅仅讨论第一种。

Windowsclient

MySQL命令程序在Windows和Linux系统中关于字符编码处理的部分并不等效,下图是Windows系统的client字符编码转换逻辑:

c35810a128b59d552d559f10fa38fa38.png

当中的三个character变量存在于server上,而charset_info存在于client。

当client启动连接到server时。client将依据配置參数设置charset_info为指定编码,同一时候通知server让server把三个character变量设置为同样编码。

传输数据流程

client从控制台标准输入读取一行命令文本。其编码为操作系统编码。

client将命令从系统编码转码为clientcharset_info变量设定的编码;

client将命令文本发送给server;

server把收到的文本解码为character_set_client编码,这个编码通常与clientcharset_info一致;

server把命令文本转码为character_set_connection。

server运行命令,产生结果。

将结果转码为character_set_results发送给client。

client把收到的结果解码为charset_info编码,这个编码通常与character_set_results一致。

client将结果转码为操作系统编码。输出到控制台标准输出。

因为在Windows平台上MySQL程序在读取控制台时使用了Unicode Console Read API,所以程序从控制台获取的原始字符串实际上是UTF16编码。所以这里的“操作系统编码”并非Windows通常的GBK,而应该看做UTF16。

Linuxclient

下图是Linux系统中的MySQLclient程序字符编码转换逻辑:

66991630d221c177346741a9c0f42bf1.png

它与Windows版的不同之处就在于。它并不把来自终端标准输入的操作系统编码字符串强制转换为charset_info编码,也不会把输出到终端的charset_info编码结果字符串强制转换为操作系统编码。

也就是说,Linux平台的MySQL程序这时候会会忽略charset_info变量。当然。这样一来Linuxclient的传输数据流程就比Windowsclient相应地少几步。

乱码陷阱模拟

依据Linux平台MySQL程序的这一特点,非常easy产生这样一个可能的陷阱:在Linux系统中通过MySQLclient向数据库插入中文数据后,查询结果没有乱码,但从配置正确的Windows平台MySQLclient查询同一个表得到的却是乱码。

能够这样模拟上述的情况:

创建一个表。当中仅仅包括一个GBK字符串字段和UTF8字符串字段。

Linux中启动MySQL连接到数据库server,将server的三个character变量从默认的UTF8改动为GBK。向数据库插入中文数据,马上select,结果无异常:

5b629a76a183aa100df8d33b2d9c70a9.png

可是使用Windows的MySQLclient查询时。结果却是乱码:

263963a62c6b7f6d52a4e9a901c86816.png

乱码分析

结合前面的传输数据流程,就能知道问题出在什么地方:

client从终端读取了一行utf8编码(Linux默认)的命令文本,忽略charset_info变量。直接把文本发送给server。

server由于事先的命令charset gbk把三个character变量都设置为了GBK。所以server觉得收到的文本是GBK编码;

接下来server会不经过不论什么转码将文本字符串直接存入数据表中,由于数据表第一个字段也是GBK。

到这里为止。数据表中存了一个UTF8字符串,而server却当它是GBK,在同一个Linuxclient查询时:

表中的字符串不经过不论什么转码直接发给client,由于character_set_results也是GBK。

client收到查询结果后由于忽略charset_info而直接不经过转码输出到终端标准输出;

终端得到的数据实际上是UTF8编码的,所以正常输出。

在Windowsclient查询时:

表中的字符串(UTF8)不经过不论什么转码直接发给client,由于character_set_results也是GBK;

client收到查询结果后觉得是charset_info编码(此时为GBK);

client把查询结果从charset_info转码为UTF16,然后调用Unicode Console Write API输出。看到乱码。

乱码“修复”

假设Windowsclient也想看到正确的结果,那就要有益错误地配置:

运行命令charset utf8,这会将charset_info和三个servercharacter都设置为UTF8;

运行命令set names gbk,这仅仅会将三个servercharacter设置为GBK;

如今select,结果看上去不再乱码了。

8ecc00bf6909195c6ae9ba38bd1f488f.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值