关系数据库-5-[mysql5]的编码问题charset=utf8

参考mysql编码问题——charset=utf8你真的弄明白了吗?
详细介绍客户端字符集、联接器connection、MySQL server字符集的设置。

1 明确问题

1.1 什么是字符集

所有数据在计算机底层都是以二进制形式保存。

将字符比如汉字转换为二进制的过程,称为编码。
将二进制转换为字符的过程,称为解码。

编码和解码时采用的规则,就是字符集

(1)美国常用字符集:ASCII
使用7位二进制进行编码。
总共128个字符,不支持中文。

(2)欧洲常用字符集:ISO-8895-1
使用8位二进制进行编码。
总共256个字符,不支持中文。

(3)中国简体字字符集:GBK
(4)中国繁体字字符集:Big5

(5)包含世界上所有语言和字符的字符集是Unicode万国码
常见是:utf-8
可放emoji表情符号的utf8mb4
utf-16
utf-32

开发人员一般使用utf8mb4字符集
但Windows系统在中国默认字符集是GBK
乱码原因:编码和解码所使用字符集不一致

所谓容量,这里指用几个字节表示一个字符,显然用的字节越多,编码空间越大,能表示更多不同的字符,也即容量越大。

1.2 查看数据库默认字符集

mysql> show character set;查看数据库支持的所有的字符集。
mysql> status;查看系统当前状态,里面可以看到部分字符集设置。
mysql> show variables like '%char%';查看系统字符集设置,包括所有的字符集设置

(1)查看数据库支持的所有的字符集。
在这里插入图片描述
(2)查看系统当前状态,里面可以看到部分字符集设置
在这里插入图片描述
(3)查看系统字符集设置,包括所有的字符集设置
在这里插入图片描述

1.3 当前电脑使用的字符集

打开电脑黑窗口(CMD),接着在空白边框点击鼠标右键,然后选择属性,并查看"选项"这一栏。可以看到CMD中输入文字使用的字符编码是GBK。
在这里插入图片描述

1.4 建表语句引出的问题

create database mytest;
use mytest;

(1)建表时指定charset=utf8

create table student1(
	sid int primary key auto_increment,
	sname varchar(20) not null,
	age int
)charset=utf8;
insert into student1(sname,age) values ("songjiang",40);
insert into student1(sname,age) values ("林冲",32);
select * from student1;

在这里插入图片描述
当建表时指定charset=utf8的时候,此时可以插入中文,并且不乱码。
(2)建表时不指定charset=utf8

create table student2(
	sid int primary key auto_increment,
	sname varchar(20) not null,
	age int
);
insert into student2(sname,age) values ("songjiang",40);
insert into student2(sname,age) values ("林冲",32);
select * from student2;

在这里插入图片描述
当我们建表不指定 charset=utf8,此时插入中文,会报错。ERROR 1366 (HY000): Incorrect string value: ‘\xC1\xD6\xB3\xE5’ for column ‘sname’ at row 1。

1.5 定位问题

在这里插入图片描述
建表时我们指定charset=utf8。
客户端client输入的字符,都是采用GBK编码的。
mysql服务器存储的字符又是UTF8编码的。
那么,我们向数据库中插入数据,从数据库中查找数据,返回到界面中,要想保证字符不乱码,肯定是经过了"编码转换过程的"。
究竟是什么东西完成了这个编码的转换过程的?
在这里插入图片描述
通过上图我们可以看到有一个东西,叫做"connection",中文名叫做"连接器"。"连接器"就是那个问题的答案。也就是说:这个转换过程依赖的就是这个connection。

2 连接器

2.1 连接器的作用与工作流程

一、连接器的作用
连接客户端与服务端,进行字符集的转换。
连接器有这种自动转换的功能。

二、连接器的工作流程
(1)客户端的字符先发给连接器,连接器选择一种编码将其转换,进行临时存储。
转换之后的编码,与连接器的编码格式一致。

(2)接着,连接器再次转换成服务器需要的编码,并最终存储在服务器中。

(3)然后,服务器返回的结果,再次先通过连接器,连接器将其转化为与客户端一致的字符集,就可以在客户端正常显示了。

2.2 连接器的字符集是UTF8

在这里插入图片描述
在CMD窗口中输入的字符,采用的字符集是GBK,也就是说客户端(client)的字符集是GBK。而写入到数据库中数据采用什么格式写入,我们在建表的时候已经指明了"charset=utf8",也就是说,mysql服务器(server)的字符集是UTF8。

假如说连接器的字符集是UTF8,这个写入数据库的过程是怎么进行的呢?
(1)首先,在客户端输入的字符,使用的字符集是GBK。
当经过连接器的时候,连接器会进行"字符集的自动转换",将原来的以GBK进行编码字符转换为以UTF8格式的编码字符,临时存储在连接器中。

(2)接着,连接器发现mysql服务器使用的字符集,与自身字符集完全一致,都是UTF8。于是,直接发给mysql服务器,进行最终的存储。

当我们从mysql服务器查数据的时候,返回过程又是怎么进行的呢?
(1)首先 ,mysql服务器会将结果以UTF8编码格式进行返回,通过连接器的时候,连接器发现mysql服务器的字符集,与自身字符集一致,于是顺利通过连接器。
(2)当连接器准备将结果发送给客户端的时候,发现客户端要求返回的字符集是GBK。因此,连接器会进行"字符集的自动转换",将以UTF8编码的结果()转换为以GBK编码的结果,进行显示,并最终发送给客户端,显示在CMD窗口中。

2.3 连接器的字符集是GBK

在这里插入图片描述
假如说连接器(connection)的字符集是GBK,这个过程又该是怎么进行的呢?
(1)首先,在客户端输入的字符,使用的字符集是GBK。当经过连接器的时候,连接器发现客户端发送过来的字符的字符集,与自身字符集相同,因此顺利通过了连接器。

(2)接着,当字符通过连接器发送给mysql服务器进行存储的时候,发现mysql服务器的字符集是UTF8,与自身的字符集GBK并不一致。因此,连接器此时又会进行"字符集的自动转换",将以GBK进行编码的字符转换为以UTF8格式的编码,转换完成以后,再次发送给mysql服务器,进行最终的存储。

当我们从mysql服务器查数据的时候,返回过程又是怎么进行的呢?
(1)首先 ,mysql服务器会将结果以UTF8编码格式进行返回,通过连接器的时候,连接器发现mysql服务器的字符集,与自身的字符集并不一致,于是连接器会进行"字符集的自动转换",将以UTF8进行编码的结果转换为以GBK格式的编码。
(2)接着连接器又将转换后的结果,准备发送给客户端,此时发现客户端的字符集,与自身的字符集一致。因此直接发送给客户端,成功在CMD窗口中显示。

3 代码演示过程

set character_set_client=gbk;设置客户端的字符集
set character_set_connection=utf8;设置连接器的字符集
set character_set_results=gbk;设置返回结果的字符集

要想不乱码,需要指定客户端的编码,让连接器不理解错误,这样就不会存入错误数据。
往回取数据的时候,还要告诉连接器,如果你从服务器返回,你应该给我转成什么格式。
因此,一共需要设置3个参数:
1、客户端发送的编码;
2、连接器使用的编码;
3、返回数据的编码;

3.1 连接器字符集UTF8

一、当前的情况是:客户端是GBK,服务器最终存储的是UTF8。

(1)因此,你就要明确告诉服务器,我的客户端是GBK的。
set character_set_client=gbk;
(2)再告诉连接器,使用UTF8。
set character_set_connection=utf8;
(3)再告诉,如果你返回值给我看的话,也请返回GBK。
set character_set_results=gbk;

在这里插入图片描述

insert into student1(sname,age) values ("武松",32);

在这里插入图片描述

二、我的客户端是GBK,但是我偏要骗对方是UTF8。
在这里插入图片描述

set character_set_client=utf8;
insert into student1(sname,age) values ("西门庆",32);

报错如下
ERROR 1366 (HY000): Incorrect string value: '\xCE\xF7\xC3\xC5\xC7\xEC' 
for column 'sname' at row 1
此时,"西门庆"对应的GBK的内码,转换成UTF8,压根就出错,不允许插入。

三、我偏要对方返回给我的数据是UTF8。
在这里插入图片描述

set character_set_client=gbk;
set character_set_results=utf8;

在这里插入图片描述

3.2 连接器字符集GBK

一、client、connection、server字符集设置的都是GBK,不会导致乱码。
如果三者都是GBK,可以简写成如下形式:set names gbk;
在这里插入图片描述

声明客户端是GBK;
set character_set_client=gbk;
声明连接器是GBK;
set character_set_connection=gbk;
声明返回值是GBK;
set character_set_results=gbk;

插入中文数据

insert into student1(sname,age) values ("西门庆",32);

在这里插入图片描述
二、现在,我偏偏声明连接器的字符集是latin1。
在这里插入图片描述

set character_set_connection=latin1;

插入中文数据

insert into student1(sname,age) values ("潘金莲",32);

在这里插入图片描述

3.3 产生乱码的两个原因

(1)解码与实际编码,不一致导致的乱码,可修复。
在这里插入图片描述

(2)在传输过程中,由于编码不一致,导致部分字节丢失,造成的乱码,不可修复。
在这里插入图片描述

4 系统默认情况

在这里插入图片描述
我们使用图中的这个命令,可以查看系统所有的字符集的设置。
从图中可以清楚的看到,客户端的字符集默认是gbk,连接器的字符集默认是gbk,返回值的字符集是gbk,mysql服务器的字符集默认是latin1。

上述设置,是不是和图二中的情况,非常相似。唯一不同的就是系统默认mysql服务器的字符集是latin1,而图二中mysql服务器的字符集是utf8。
在这里插入图片描述
系统为什么将mysql服务器默认使用latin1字符集?

为什么要这么设置呢?因为latin1不支持中文,当我们插入中文的时候,当客户端发送过去的字符,通过连接器,最后发送给mysql服务器的时候,连接器发现mysql服务器采用的字符级是latin1,字符集由gbk转化为latin1,就相当于大鱼过小渔网一样,一定会掉肉,而对于字符集来说就会丢失字节。丢失字节后存入的值,肯定也就是错误的,不正确的。

由于mysql的检测是很严格的,既然你存入的时候都会丢失字节,那么存入的值肯定也是错误的,因此,我索性就不让你插入。“这就是我们不设置mysql服务器字符集,想要插入中文,提示1366错误的原因。”"ERROR 1366 (HY000): Incorrect string value: ‘\xD5\xC5\xC8\xFD’ ““for column ‘sname’ at row 1”

当我们使用"charset=utf8"命令,将mysql服务器的字符集设置为utf8后,由于utf8是支持中文的,utf8是变长字符集,它能够支持全世界所有国家的语言。因此,当你输入一个以gbk格式编码的中文,在utf8中肯定是也有自己的一套编码格式,显示同样的文字(只不过此时是以utf8编码的)。

最后用一个不那么恰当的比喻,来说明字符集编码。
拿一本新华字典(汉语字典),再拿一本牛津字典(英语字典)。此时,我们要查找一个同一个词"中国”,在汉语字典中,"中国"采用的编码是zhongguo,但是在牛津字典中,“中国"采用的编码是china,你非要拿着zhongguo去牛津字典中查"中国”,你觉得你得到的结果是正常显示,还是乱码呢?

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

皮皮冰燃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值