深入了解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" 原 ...
随机推荐
- 关于tomcat下startup.bat双击闪退的问题
背景:之前做单点登录,复制了几个tomcat,改了各自端口,当做不同服务器用. 今天无意间随便点击了一个tomcat下的startup.bat批处理文件,结果出来控制台,没出几行信息就闪退了.点击其他 ...
- Spring AOP 和 动态代理技术
AOP 是什么东西 首先来说 AOP 并不是 Spring 框架的核心技术之一,AOP 全称 Aspect Orient Programming,即面向切面的编程.其要解决的问题就是在不改变源代码的情 ...
- java webservice简单的例子
开发环境:eclipse .jdk 创建服务端 demo-webservice 创建类 HelloService.java package com.hundsun.ws.service; import ...
- (转)java并发之Executor
场景: 线程池在面试时候经常会碰到,在工作中用的场景更多,所以很有必要弄清楚. 1 简介 Java自1.5以来加入了处理一批线程的方法,也就是java并发包里的Executor.本文主要介绍Execu ...
- iOS开发 MVVM+RAC 的使用
好长一段时间没有敲简书了! 主要是因为一直在跑面试. 终于还是在上海入职了! 由于项目原因最终还是入了MVVM+RAC的坑 下面是正题. Demo效果 使用MVVM+RAC请求网络数据 Reactiv ...
- Django中ORM模型总结(一)[概述,查询语句]
理解ORM框架 概述 O:(objects)->类和对象. R:(Relation)->关系,关系数据库中的表格. M:(Mapping)->映射. 作用: 可以通过类和类对象就可以 ...
- phpunit实践笔记
phpunit成为单元测试的代名词已成为共识, 但很多在实际编写测试过程中遇到的很多问题通过手册.网上搜索都很难找到相关资料, 大部分都得通过查看源代码和实践的代码经验解决.欢迎大家拍砖.(在此之前请 ...
- jsp元素
1.指令元素:用于在JSP转换为Servlet阶段提供JSP页面的相关信息,如页面采用的字符编码集.页面中需要导入的类等信息,指令元素不会产生任何的输出到当前JSP的输出流中 指令元素有三种指令:pa ...
- ajax访问controller,无法通过return $this->goHome()跳转
第一次在yii2中使用ajax来请求controller,做的是第三方登录,facebook和google登录. 登录成功应该跳转到首页,想当然的以为用return $this->goHome( ...
- SMBLoris windows拒绝服务漏洞
在美国拉斯维加斯举行的2017年度DEF CON黑客大会上,安全研究人员公布了Windows系统上的一个长达20年没有发现的漏洞,该漏洞名为"SMBLoris",黑客可以轻松的使用 ...