深入了解mysql数据传输编码原理
一、基本概念(这里引用http://www.laruence.com/2008/01/05/12.html)
1、 给定一系列字符,对每个字符赋予一个数值,用数值来代表对应的字符,这一数值就是字符的编码(Encoding)。例如,我们给字符’A'赋予数值0,给字符’B'赋予数值1,则0就是字符’A'的编码;
2、 给定一系列字符并赋予对应的编码后,所有这些字符和编码对组成的集合就是字符集(Character Set)。例如,给定字符列表为{‘A’,'B’}时,{‘A’=>0, ‘B’=>1}就是一个字符集;
3、字符序(Collation)是指在同一字符集内字符之间的比较规则;
4、确定字符序后,才能在一个字符集上定义什么是等价的字符,以及字符之间的大小关系;
5、每个字符序唯一对应一种字符集,但一个字符集可以对应多种字符序,其中有一个是默认字符序(Default Collation);
6、MySQL中的字符序名称遵从命名惯例:以字符序对应的字符集名称开头;以_ci(表示大小写不敏感)、_cs(表示大小写敏感)或_bin(表示按编码值比较)结尾。例如:在字符序“utf8_general_ci”下,字符“a”和“A”是等价的;
二、名词解释
1、character_set_client:客户端数据解析、编码的字符集。
2、character_set_connection:连接层字符集。
3、character_set_server:服务器内部操作字符集。
4、character_set_results:查询结果字符集。
5、character_set_database:当前数据库的字符集。
6、character_set_system:系统源数据(字段名等)字符集。
注:
1、还有以collation_开头的同上面对应的变量,用来描述字符序。
2、服务端编码、解析时,是按照前一环节的编码进行解析的,按照各自的字符集进行编码的。
3、character_set_server是mysql数据库内存的操作字符集。如果创建数据库时,没有指定数据库的字符集,则使用character_set_server的字符集作为默认字符集;如果创建表时,没有指定表的字符集,则使用character_set_database的字符集作为默认字符集;如果在创建字段时,没有指定字段的字符集,则使用表的字符集作为默认字符集。
4、set names gbk;等同于同时设置character_set_client,character_set_connection,character_set_results这三个字符集。
三、数据传输过程中字符集编码、解析
1.客户端以及编码

我们使用jdbc操作数据的程序、navicate操作工具、操作系统操作数据库这些都认为是客户端。客户端navicate的编码为utf8,windows默认的编码为gbk。一般情况下,utf8编码的中文占三个字节,gbk占用两个字节(一个字节是8位二进制,也就是两个十六进制)。
Navicate操作(utf8)
mysql> show variables like '%char%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | utf8 |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | utf8 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set
mysql> select hex('我很帅');
+--------------------+
| hex('我很帅') |
+--------------------+
| E68891E5BE88E5B885 |
+--------------------+
1 row in set
Windows上操作(gbk)
mysql> show variables like '%char%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | gbk |
| character_set_connection | gbk |
| character_set_database | utf8 |
| character_set_filesystem | binary |
| character_set_results | gbk |
| character_set_server | utf8 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set
mysql> select hex('我很帅');
+--------------------+
| hex('我很帅') |
+--------------------+
| CED2BADCCAA7 |
+--------------------+
1 row in set
2.解析过程
a.sql语句通过客户端编码发送到mysql服务器上;
b.character_set_client对接收到的数据进行解码,这里解码按照character_set_client编码进行解码,最后按照自身字符集进行编码。
c.character_set_connection收到来自client的编码,这里进行字符集转换。注意这里s.decode(character_set_client).encode(character_set_connection)。
d.character_set_server这里是服务器内部使用的字符集,如果单独给字段添加字符集,这里取的是字段字符集。这里收到connection的编码,进行字符集转换。e.decode(character_set_connection).encode(character_set_server)。
3.查询过程
a.mysql服务器转换为character_set_results发送到客户端,其实这里你只要知道最后从服务器出来的时候是按照character_set_results编码的。
b.发送到客户端之后,按照客户端编码进行解码。所以如果character_set_results和客户端编码不一致,会导致查询乱码。
ps:这里我创建一个gbk表,里面插入有数据(自己构造,带有中文)。
Navicate操作(utf8) mysql> select @@character_set_results; +-------------------------+ | @@character_set_results | +-------------------------+ | utf8 | +-------------------------+ 1 row in set mysql> select name_man from wsyy_marry where id = 1; +----------+ | name_man | +----------+ | 赫立广 | +----------+ 1 row in set mysql> set @@session.character_set_results = 28; Query OK, 0 rows affected mysql> select @@character_set_results; +-------------------------+ | @@character_set_results | +-------------------------+ | gbk | +-------------------------+ 1 row in set mysql> select name_man from wsyy_marry where id = 1; +----------+ | name_man | +----------+ | ������ | +----------+ 1 row in set
Windows操作(gbk) mysql> select @@character_set_results; +-------------------------+ | @@character_set_results | +-------------------------+ | gbk | +-------------------------+ 1 row in set mysql> select name_man from wsyy_marry where id = 1; +----------+ | name_man | +----------+ | 赫立广 | +----------+ 1 row in set mysql> set @@session.character_set_results = 33; Query OK, 0 rows affected mysql> select @@character_set_results; +-------------------------+ | @@character_set_results | +-------------------------+ | utf8 | +-------------------------+ 1 row in set mysql> select name_man from test.wsyy_marry where id = 1; +----------+ | name_man | +----------+ | 璧珛骞� | +----------+ 1 row in set
四、总结
1、字符集设置33,代表utf8;28代表gbk字符集设置33;
2、字符集出现乱码的地方最大可能在两个地方,character_set_client和character_set_results。如果这两个地方的编码个客户端编码不一致会乱码。告诉你,有可能存都存不进去。
3、后面也有可能出现编码问题,如果中文字符串,latin1解码不了中文,则会出现乱码。也就是说进行编码转换的时候可能出现不兼容的情况,latin1编码的都能被utf8兼容,反之就可能出现”??”这样的情况。
4、看下来之后老老实实不要乱设置character_set_client这些值。如果能保持所有的都是utf8,那肯定没问题。
五、疑问
|
客户端编码 |
client |
connection |
server |
结果 |
|
utf8 |
gbk |
gbk |
gbk/utf8 |
插入失败 |
|
utf8 |
gbk |
utf8 |
gbk/utf8 |
插入乱码 |
|
utf8 |
utf8 |
gbk |
gbk/utf8 |
正常插入 |
|
utf8 |
urf8 |
utf8 |
gbk/utf8 |
正常插入 |
我做了如下统计,客户端编码和character_set_client编码不一致有可能出现插入乱码,也有可能出现数据插都插不进去。我也不知道为啥会不能插入数据库。下面这两种情况很大都是可能是乱码导致的报错。
1、Incorrect string value: '\xB6' for column 'NAME_MAN' at row 1。
2、SQLException errorcom.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column 'NAME_MAN' at row 1。
如果对这里面介绍有异议或者能有更全面的理解可以在下面留言,大家共同学习。
六、参考资料
1.http://www.jianshu.com/p/96ee5b2adef3
2.http://blog.csdn.net/kxcfzyk/article/details/37723367
3.http://www.laruence.com/2008/01/05/12.html
深入了解mysql数据传输编码原理的更多相关文章
- MYSQL索引结构原理、性能分析与优化
[转]MYSQL索引结构原理.性能分析与优化 第一部分:基础知识 索引 官方介绍索引是帮助MySQL高效获取数据的数据结构.笔者理解索引相当于一本书的目录,通过目录就知道要的资料在哪里, 不用一页一页 ...
- MySQL字符集编码
MySQL字符集编码总结 之前内部博客上凯哥分享了一篇关于mysql字符集的文章,之前我对mysql字符集一块基本没有深究过,看到凯哥文章后有些地方有点疑惑,遂自己去看了mysql的官方文档,并參考了 ...
- MYSQL转换编码的解决方法
MYSQL转换编码的解决方法 一.在utf8的mysql下 得到中文‘游客’的gbk下的16进制编码 mysql> SELECT hex(CONVERT( '游客' USING gbk )); ...
- 你的MySQL服务器开启SSL了吗?SSL在https和MySQL中的原理思考
最近,准备升级一组MySQL到5.7版本,在安装完MySQL5.7后,在其data目录下发现多了很多.pem类型的文件,然后通过查阅相关资料,才知这些文件是MySQL5.7使用SSL加密连接的.本篇主 ...
- MySQL 储存过程-原理、语法、函数详细说明
Mysql储存过程是一组为了完成特定功能的SQL语句集,经过编译之后存储在数据库中,当需要使用该组SQL语句时用户只需要通过指定储存过程的名字并给定参数就可以调用执行它了,简而言之就是一组已经写好的命 ...
- 【转】由浅入深探究mysql索引结构原理、性能分析与优化
摘要: 第一部分:基础知识 第二部分:MYISAM和INNODB索引结构 1.简单介绍B-tree B+ tree树 2.MyisAM索引结构 3.Annode索引结构 4.MyisAM索引与Inno ...
- H264编码原理以及I帧、B和P帧详解, H264码流结构分析
H264码流结构分析 http://blog.csdn.net/chenchong_219/article/details/37990541 1.码流总体结构: h264的功能分为两层,视频编码层(V ...
- xss的编码原理
把以前的笔记翻出来整理一下 最前方 xss如何选用编码原理,为什么 找到的挺清楚的文章了:https://www.cnblogs.com/p0laris/p/11898322.html浏览器解析有两种 ...
- mysql utf8编码
做微信项目,报错 "Incorrect string value: '\\xF0\\x9F\\x98\\x8B' for column 'nickname' at row 1" 原 ...
随机推荐
- 玩玩微信公众号Java版之五:获取关注用户信息
在关注者与公众号产生消息交互后,公众号可获得关注者的OpenID(加密后的微信号,每个用户对每个公众号的OpenID是唯一的.对于不同公众号,同一用户的openid不同).公众号可通过本接口来根据Op ...
- java内存区域——深入理解JVM读书笔记
本内容由<深入理解java虚拟机>的部分读书笔记整理而成,本读者计划连载. 通过如下图和文字介绍来了解几个运行时数据区的概念. 方法区:它是各个线程共享的区域,用于内存已被VM加载的类信息 ...
- 教你做炫酷的碎片式图片切换 (canvas)
前言 老规矩,先上 DEMO 和 源码.图片区域是可以点击的,动画会从点击的位置开始发生. 本来这个效果是我3年前做的,只是当是是用无数个 div 标签完成的,性能比较成问题,在移动端完全跑不动.最近 ...
- (转) Eclipse Maven 编译错误 Dynamic Web Module 3.1 requires Java 1.7 or newer 解决方案
场景:在导入Maven项目时候遇到如下错误. 1 问题描述及解决 Eclipse Maven 开发一个 jee 项目时,编译时遇到以下错误:Description Resource Path Loca ...
- showcase,开发中必须引起重视的小环节
有人说,测试者来自火星,开发者来自金星.这是因为软件测试员和软件开发者就好比一对冤家,里面的缘由说不清也道不明.开发代表着创造,而测试则代表着摧毁,因为测试的目的就是以各种方式不断地从开发出的产品中发 ...
- 【Owin 学习系列】1. 第一个 Owin 程序
IIS 中的 Owin 在 IIS 里面部署 Owin,既能得到 Owin 管道模型的灵活性和模块特性,也能很好地利用 IIS 成熟的配置,Owin 程序将会跑在 ASP.NET request 的管 ...
- 【PHP】数组用法(转)
摘要: 说明数组遍历方法foreach,while,for,推荐使用foreach(PHP内部实现,简单速度最快,还可以遍历类属性).以及一些常用方法current,prev,next,end,key ...
- 快速搭建MySQL复制集
快速搭建MySQL复制集 1 环境说明 MySQL版本 5.6 basedir :/u01/my3306 #MySQL软件目录 数据目录 :/u01/mysql/[实例名]/data 日志目录 :/u ...
- 相对路径&绝对路径
粗浅理解: 1)绝对路径:带有访问协议的路径,就是带上http访问协议 2)相对路径: ①以带斜杠开头的相对路径: A)前台相对路径:以web服务器的根路径为参照路径,比如在jsp.HTML中写的路径 ...
- elk 5.x的部署
前言 elk是由elasticsearch.logstash.kibana三者组成 其中elasticsearch主要负责数据存储与搜索 logstash主要负责收集日志信息以及对日志信息的切片索引等 ...