1、字符集基础

在计算机的眼中只有0和1,但是在人类世界中却有上百种语言,每种语言又有成千上万的文字,那么如何在计算中表示人类世界中的这些文字呢?

在上个世纪60年代的时候,美国首先定义了一套规则,在这个规则中一共定义了128个字符对应的二进制编码,比如大写的字母A是65(01000001),空格是32(00100000)等等。通过这个规则,计算机也就知道了01000001表示字母A,这也就是所谓的ASCII。在计算机中使用一个字节来存储ASCII。

很显然,只有ASCII是不够的,128个字符是远远不能表示各种语言的,这个时候各个地区也就逐渐定义了自己的编码方式,比如在欧洲的一些国家就通过启用ASCII编码的最高位来拓展支持的字符,因为在ASCII中只有128个字符,一个字节有8位,那么在ASCII中的最高位肯定是0,通过启动这个闲置的最高位就把支持的字符扩展到256个了,已经完全能满足自己地区的需求。但是,随着互联网的发展,地理上隔开的世界被一根根的网线连接在一起了,如果各个国家地区都使用自己的编码方式,显然是有问题的。于是就有了unicode,个人感觉Unicode的作用就像他的名字一样unique code,几乎给世界上的每一个符号都做了定义,如果大家都使用这个定义去做,那就不存在相互看不懂编码的问题,比如:

到此为止,已经解决了编码的问题了,但是又有了新的问题。unicode只是定义了一个字符怎么去编码,没有说明怎么去存储啊。比如“龟”在unique的代码为9F9F(1001111110011111)他需要2个字节,有的符号对应的编码更大可能需要3个字节或者更多。如何区分呢?比如0001111110011111怎么知道到底是表示两个ACSII字符还是表示一个占用2个字节的Unicod字符呢?

上面的这个问题就需要交给UTF-8(或者其他)去解决了,一句话就是Unicode定义了字符的编码,UTF-8定义了这个编码的实现(存储)方式,在Unicode的编码中,最特别的一点就是他是变长的,变长的好处就是按需求占用空间,试想一下,用3个字节去存储一个单字符划算吗?在UTF-8的实现规则中只有2点:

对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。

对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。

当然,这个规则不是我要了解的重点,只需要知道unicode定义了字符的编码,UTF-8是一种实现Unicode的方式就好。

2、Mysql中的字符集参数

看一下Mysql中和字符集相关的参数

mh01@3306>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/local/mysql-5.7.16-linux-glibc2.5-x86_64/share/charsets/ |

+--------------------------+---------------------------------------------------------------+

8 rows in set (0.00 sec)

复制代码

2.1创建对象相关

根据上面的相关variable,先看看和创建对象相关的变量。

character_set_server,这个变量为创建DB时候的默认值,Mysql在创建对象的时候有一个阶梯状的规则。如果创建database的时候没有指定这个db的字符集,就使用character_set_server的值;如果在创建表的时候没有指定字符集就使用这个表所在db的字符集,如果创建列的时候没有指定字符集,就使用这个表的字符字符集。

2.2服务器和客户端通信相关

这个是主要的参数,这部分的参数主要有character_set_client、character_set_connection、character_set_results这几个

首先看一下character_set_client,这个定义了客户端传输的字符集,用来告诉Mysql Server,客户端使用character_set_client的值来传输数据。也就是说Mysql总是认为客户端传输的是用该参数对应的编码来写的,但是真实情况却不一定,如果这个参数设置错误,可能会导致乱码,详情可以看后续的测试部分。

character_set_connection,Mysql需要把字符集转换为character_set_connection来处理SQL语句

charcter_set_results,这个参数定义了用何种字符集返回给客户端。

下图是Mysql在处理客户端和服务器通信时候字符集的转换方式:

转换规则:如果 character_set_client 和 character_set_connection 一样,或者当前的字符编码是和ASCII兼容,并且都是ASCII范围内的,就不转换,其它情况就转。

2.3其它

character_set_system是一个只读变量,说明元数据的编码方式

character_set_database表示了当前数据库的默认字符集,比如在使用use切换数据库的时候,该参数会随着当前数据库默认字符集的改变而改变。

3、修改他们会有什么影响

在一般实践中,经常会使用set names UTF8的方式去设置相关的字符集参数,这种方式一般是同时修改了三个变量分别是

SET character_set_client = UTF8;

SET character_set_results = UTF8;

SET character_set_connection = UTF8;

复制代码

为什么要同时这个这三个参数,如果这个三个参数不一致会发生什么情况。

先创建一个表,用UTF8的方式插入一些数据

CREATE TABLE `char_test` (

`id` int(11) DEFAULT NULL,

`name` varchar(20) DEFAULT NULL

) ENGINE=InnoDB DEFAULT CHARSET=utf8

set names utf8;

mh01@3306>insert into char_test (1,'哈哈');

mh01@3306>select id,name,hex(name) from char_test;

+------+--------+--------------+

| id | name | hex(name) |

+------+--------+--------------+

| 1 | 哈哈 | E59388E59388 |

+------+--------+--------------+

1 row in set (0.00 sec)

复制代码

使用UTF8的终端(也就意味中客户端的字符集都是UTF8)插入了一条数据,发现目前显示都正确。

3.1修改character_set_client的值

mh01@3306>set character_set_client=gbk;

Query OK, 0 rows affected (0.00 sec)

mh01@3306>insert into char_test values (2,'哈哈');

Query OK, 1 row affected (0.01 sec)

mh01@3306>select id,name,hex(name) from char_test;

+------+-----------+--------------------+

| id | name | hex(name) |

+------+-----------+--------------------+

| 1 | 哈哈 | E59388E59388 |

| 2 | 鍝堝搱 | E98D9DE5A09DE690B1 |

+------+-----------+--------------------+

2 rows in set (0.00 sec)

复制代码

从测试中可以看出,现在已经出现乱码了。为什么?

客户端使用的是UTF8,那么在发送“哈哈”的时候就会使用“E59388E59388”的编码去发送,这里的“哈哈”占用了6个字节。

当Mysql Server接收到这个字符的时候,根据character_set_client的值,Mysql认为客户端是用GBK做编码的,这里就出现问题了因为实际上客户端使用的是UTF8的编码。根据上面提到的转换规则(character_set_client的值和character_set_connection的值不一样)就会发生字符集的转换。因为Mysql认为这个编码是GBK的编码,所以就认为“E59388E59388”是三个字符(对应的汉子就是“鍝堝搱”),然后把“鍝堝搱”三个字符转换为UTF8,所以最终会发现id=2的值居然多了3字节。因为Mysql从一开始就是把UTF8的编码当成了GBK的编码去理解,理解错了自然最终的存储也就错了。

3.2修改character_set_connection

mh01@3306>set names utf8;

Query OK, 0 rows affected (0.00 sec)

mh01@3306>set character_set_connection=gbk;

Query OK, 0 rows affected (0.00 sec)

mh01@3306>insert into char_test values (3,'哈哈');

Query OK, 1 row affected (0.01 sec)

mh01@3306>select id,name,hex(name) from char_test;

+------+-----------+--------------------+

| id | name | hex(name) |

+------+-----------+--------------------+

| 1 | 哈哈 | E59388E59388 |

| 2 | 鍝堝搱 | E98D9DE5A09DE690B1 |

| 3 | 哈哈 | E59388E59388 |

+------+-----------+--------------------+

3 rows in set (0.00 sec)

复制代码

正常显示,为什么?客户端的编码是UTF8,Mysql Server收到后根据character_set_client的设置认为是UTF8编码(答对了),但是因为character_set_connection的编码是GBK,需要进行转换。和第一个例子不一样的地方是,在这里Mysql的理解是正确的(上一个例子中Mysql是误把“哈哈”理解为“鍝堝搱”),所以Mysql会正确的把UTF8编码转换为GBK编码。最后,由于表的编码是UTF8,所以Mysql又把GBK转换为UTF8编码存储起来,这个过程无非就是做了一些无谓的转换,但是结果是正常的。

3.3只修改character_set_results

mh01@3306>set character_set_results=gbk;

Query OK, 0 rows affected (0.00 sec)

mh01@3306>insert into char_test values (4,'哈哈');

Query OK, 1 row affected (0.01 sec)

mh01@3306>select id,name,hex(name) from char_test;

+------+--------+--------------------+

| id | name | hex(name) |

+------+--------+--------------------+

| 1 | | E59388E59388 |

| 2 | 哈哈 | E98D9DE5A09DE690B1 |

| 3 | | E59388E59388 |

| 4 | | E59388E59388 |

+------+--------+--------------------+

4 rows in set (0.00 sec)

复制代码

因为character_set_connection、character_set_client、客户端、表都是使用UTF8编码,所以在存储的时候存储的是正确的编码,“哈哈”=E59388E59388。因为character_set_results是GBK,所以做了一次转换,注意这次转换也是正常的转换,问题出在客户端这里,Mysql使用GBK编码把结果返回给客户端,但是客户端的使用的UTF8的,客户端没那么聪明,他会认为自己收到的都是UTF8的编码,但是实际上他收到的编码是GBK的编码,所以这回是客户端理解错误了,也就是显示出了错误的结果。

有意思的是,为什么id=2的显示正常?因为在id=2的插入过程中,使用了UTF8-->错误理解为GBK编码--->转换为UTF8的方式,而返回的时候,因为server会将存的UTF8又给转回GBK,然后客户端又拿着这个GBK误以为是UTF8解析,实际上就是一个逆向过程,类似负负得正~

4 参考

mysql中基字符集_Mysql中的字符集相关推荐

  1. mysql获取当月最后一天_mysql中获取本月第一天、本月最后一天、上月第一天、上月最后一天

    mysql获取当月最后一天_mysql中获取本月第一天.本月最后一天.上月第一天.上月最后一天等等 转自: https://blog.csdn.net/min996358312/article/det ...

  2. mysql是哪五个字符集_MySQL中涉及的几个字符集

    character-set-server/default-character-set:服务器字符集,默认情况下所采用的. character-set-database:数据库字符集. characte ...

  3. mysql数据库blob区别_MySQL中TEXT与BLOB字段类型的区别

    在MySQL中有两个字段类型容易让人感觉混淆,那就是TEXT与BLOB,特别是自己写博客程序的博主不知道改为自己的博客正文字段选择TEXT还是BLOB类型. 下面给出几点区别: 一.主要差别 TEXT ...

  4. mysql中text格式化_mysql中char,varchar,text

    1.char char最大长度是255字符,注意是字符数和字符集没关系. 1)可以有默认值, 2)尾部有空格会被截断 3)不管汉字.英文,还是其他编码,都可以存255字符 2.varchar 1)va ...

  5. mysql的英文字母_MySQL中查询的有关英文字母大小写问题的分析

    mysql数据库在做查询时候,有时候是英文字母大小写敏感的,有时候又不是的,主要是由mysql的字符校验规则的设置决定的,通常默认是不支持的大小写字母敏感的. 1. 什么是字符集和校验规则? 字符集是 ...

  6. mysql create database 语法_MySQL中CREATE DATABASE语法总结

    CREATE DATABASE是mysql创建数据库的命令. CREATE DATABASE的语法如下: CREATE {DATABASE | SCHEMA} [IF NOT EXISTS] db_n ...

  7. mysql乱码的问题_MySQL中出现乱码问题的终极解决宝典

    MySQL出现乱码的原因 要了解为什么会出现乱码,我们就先要理解:从客户端发起请求,到MySQL存储数据,再到下次从表取回客户端的过程中,哪些环节会有编码/解码的行为.为了更好的解释这个过程,博主制作 ...

  8. mysql varchar2多少合适_MySQL中varchar最大长度是多少(仅学习)

    目录 一. varchar存储规则: 二. varchar和char 的区别: ps :被问到一个问题:MySQL中varchar最大长度是多少? 1.限制规则 2.计算例子 3.varchar物理存 ...

  9. mysql replace报错_Mysql中replace与replace into的用法讲解

    Mysql replace与replace into都是经常会用到的功能:replace其实是做了一次update操作,而不是先delete再insert:而replace into其实与insert ...

最新文章

  1. 关于javascript的介绍
  2. 勒索软件可能已被“终极”解决
  3. pythonos基础_python基础之模块之os模块
  4. Marketing Cloud的contact merge机制
  5. linux hadoop 运行jar,Linux下执行Hadoop WordCount.jar
  6. shopee虾皮科技测试工程师第一次笔试
  7. 不同.net版本实现单点登录
  8. ubuntu19.04支持android,Ubuntu 19.04 最终发布日期和计划功能公布
  9. 仿souhu页面设计
  10. 曾经用过的Cookie
  11. JS学习总结(1)——基础知识
  12. PS 在PS中如何等比例放大缩小图片
  13. eleme Html CSS 设置鼠标停靠显示图片
  14. 人工智能产品经理知识体系和学习计划
  15. 网线有网,路由器连接之后没网,解决办法
  16. PPT模板免费下载制作
  17. spring boot电商系统前端界面设计与浏览器兼容性研究 毕业设计-附源码231058
  18. 求N个数中的第二大的数字
  19. mysql中有没有FM_关于FM数据库,简单介绍一下
  20. 蓝牙室内定位方案-灵思科

热门文章

  1. Labview与OPC协议数据采集
  2. blockly开始使用
  3. 【报告分享】2021中国咖啡行业发展白皮书-消费界(附下载)
  4. mysql 随机取几万数据,mysql随机取数据的几种方法
  5. poi操作文档转为输入流
  6. CS224N-子词模型(subwords)
  7. 龙腾7寸工业液晶屏M070AWPA R0参数资料-7寸高亮屏
  8. 【常见 error】Vivado生成比特流时报错[DRC NSTD-1]和[DRC UCIO-1]
  9. 如何快速学习abaqus复合材料--【理论+实操】
  10. hls二次加密 m3u8_加密的m3u8、ts文件合并