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

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

Windowsclient

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

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

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

传输数据流程

  1. client从控制台标准输入读取一行命令文本。其编码为操作系统编码。
  2. client将命令从系统编码转码为clientcharset_info变量设定的编码;
  3. client将命令文本发送给server;
  4. server把收到的文本解码为character_set_client编码,这个编码通常与clientcharset_info一致;
  5. server把命令文本转码为character_set_connection。
  6. server运行命令,产生结果。
  7. 将结果转码为character_set_results发送给client。
  8. client把收到的结果解码为charset_info编码,这个编码通常与character_set_results一致。
  9. client将结果转码为操作系统编码。输出到控制台标准输出。

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

Linuxclient

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

它与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,结果无异常:

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

乱码分析

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

  1. client从终端读取了一行utf8编码(Linux默认)的命令文本,忽略charset_info变量。直接把文本发送给server。
  2. server由于事先的命令charset gbk把三个character变量都设置为了GBK。所以server觉得收到的文本是GBK编码;
  3. 接下来server会不经过不论什么转码将文本字符串直接存入数据表中,由于数据表第一个字段也是GBK。

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

  1. 表中的字符串不经过不论什么转码直接发给client,由于character_set_results也是GBK。
  2. client收到查询结果后由于忽略charset_info而直接不经过转码输出到终端标准输出;
  3. 终端得到的数据实际上是UTF8编码的,所以正常输出。

在Windowsclient查询时:

  1. 表中的字符串(UTF8)不经过不论什么转码直接发给client,由于character_set_results也是GBK;
  2. client收到查询结果后觉得是charset_info编码(此时为GBK);
  3. client把查询结果从charset_info转码为UTF16,然后调用Unicode Console Write API输出。看到乱码。

乱码“修复”

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

  1. 运行命令charset utf8,这会将charset_info和三个servercharacter都设置为UTF8;
  2. 运行命令set names gbk,这仅仅会将三个servercharacter设置为GBK;
  3. 如今select,结果看上去不再乱码了。

MySQL的字符编码体系(二)——传输数据编码的更多相关文章

  1. MySQL的字符编码体系(一)——数据存储编码

    安装MySQL好多次了,每次都会纠结于数据库的字符编码配置,所以我决定这一次彻底把它理清. MySQL的字符编码结构比較细,它慷慨向分为两个部分:数据存储编码和传输数据编码.本篇讨论数据存储编码部分, ...

  2. Mysql 的字符编码机制、中文乱码问题及解决方案【转载】

    本文转载自:http://hi.baidu.com/huabinyin/item/7f51e462df565c97c4d24929.感谢作者及相关博主.        相信很多朋友都会对字符编码敬而远 ...

  3. Linux下修改MySQL数据库字符编码为UTF-8解决中文乱码

    由于MySQL编码原因会导致数据库出现乱码. 解决办法: 修改MySQL数据库字符编码为UTF-8,UTF-8包含全世界所有国家需要用到的字符,是国际编码. 具体操作: 1.进入MySQL控制台 &g ...

  4. ubuntu下修改mysql默认字符编码出现的Job failed to start解决办法

    ubuntu下修改mysql默认字符编码出现的Job failed to start解决办法 前几天卸掉了用了好多年的Windows,安装了Ubuntu12.04,就开始各种搭环境.今天装好了MySQ ...

  5. 【JAVA编码】 JAVA字符编码系列二:Unicode,ISO-8859,GBK,UTF-8编码及相互转换

    http://blog.csdn.net/qinysong/article/details/1179489 这两天抽时间又总结/整理了一下各种编码的实际编码方式,和在Java应用中的使用情况,在这里记 ...

  6. 拨开字符编码的迷雾--MySQL数据库字符编码

    拨开字符编码迷雾系列文章链接: 拨开字符编码的迷雾--字符编码概述 拨开字符编码的迷雾--编译器如何处理文件编码 拨开字符编码的迷雾--字符编码转换 拨开字符编码的迷雾--MySQL数据库字符编码 1 ...

  7. Java 字符编码(二)Java 中的编解码

    Java 字符编码(二)Java 中的编解码 java.nio.charset 包中提供了一套处理字符编码的工具类,主要有 Charset.CharsetDecoder.CharsetEncoder. ...

  8. mysql数据库字符编码修改

    mysql数据库字符编码修改 修改数据库的字符集mysql>use mydb mysql>alter database mydb character set utf8; 创建数据库指定数据 ...

  9. python之字符编码(二)

    一.字符编码的发展史 阶段一:现代计算机起源于美国,最早诞生也是基于英文考虑的ASCII ASCII:一个Bytes代表一个字符(英文字符/键盘上的所有其他字符),1Bytes=8bit,8bit可以 ...

随机推荐

  1. Resilio-sync auto restart

    syncheck.sh #!/bin/sh if [ $(pgrep xxxrslsync) ]; then echo && date >> /home/pi/sync/s ...

  2. Shell 控制并发

    方法1: #!/bin/bash c=0 for i in `seq -w 18 31`;do while [ $c -ge 3 ];do c=$(jobs -p |wc -w) sleep 1s d ...

  3. spart快速大数据分析学习提纲(一)

    Spart是什么 Spart是一个用来实现快速而而通用的集群计算平台. 在速度方面,Spart扩展了广泛使用的Mapreduce计算模型,而且高效的支持更多的计算模式,包括交互式查询和流处理.Spar ...

  4. NET Core 静态文件及JS包管理器(npm, Bower)的使用

    NET Core 静态文件及JS包管理器(npm, Bower)的使用 文章目录 在 ASP.NET Core 中添加静态文件 使用npm管理JavaScript包 使用Bower管理JavaScri ...

  5. java枚举小结

    如何定义一个枚举类? //定义了4个等级 enum Level{ A,B,C,D } 枚举类的实质: class Level{ public static final Level A = new Le ...

  6. Perl常用特殊变量

    perl 内置变量 $- 当前页可打印的行数,属于Perl格式系统的一部分 $! 根据上下文内容返回错误号或者错误串 $” 列表分隔符 $# 打印数字时默认的数字输出格式 $$ Perl解释器的进程I ...

  7. animate基础

    用JQUERY做动画是很方便的,已经看过大牛们做出不逊色于FLASH的各种效果. 其中的基本功就有animate这个方法的使用.于是,从零开始,训练基本功: <body> <div ...

  8. Unity3d 跑酷游戏 之Character Controller篇

    unity3d  Character Controller @by  广州小龙 做3D跑酷游戏,也慢慢的学习了一些东西,从开发过程中积累了一些小的知识点跟大家分享一下! 1. 这个Revert按钮的意 ...

  9. Android Wear开发 - 数据通讯 - 第三节 : 事件处理

    http://developer.android.com/training/wearables/data-layer/events.html 以下是本人在学习官方开发文档时的笔记,主要是翻译为主,并在 ...

  10. C++ STL的各种实现版本

    ANSI/ISO的C++ STL规范版本正式通过以后,各个C++编译器厂商就可以依照标准所描述的原型去实现C++ STL泛型库,于是出现多种符合标准接口,但具体实现代码不同的泛型库,主要有: HP S ...