一、中文数据问题
1、中文数据问题本质是字符集问题(客户端和服务器的字符集不同,而服务器的字符集是可以改变的)
2、计算机只识别二进制,人类更多是识别符号(字符)。需要有一个二进制与字符的对应关系(字符集)
注:
(1)字符集:二进制与字符的对应关系
(2)字符在计算机中对应的二进制码叫做字符编码(计算机有一个特点:只能存储对应的二进制码)
(4)字符 <--> 字符集 <--> 字符编码(二进制)
(5)字符在系统中都有对应的二进制在存储
3、如果直接通过cmd下的mysql.exe进行中文数据插入,可能会出错。出错原因如下:
(1)用户是通过客户端mysql.exe来操作mysqld.exe
(2)真正的SQL执行是服务器mysqld.exe来执行
(3)mysql.exe将数据传入mysqld.exe的时候,没有告知其对应的符号规则(字符集),而mysqld.exe也没有能力自己判断,就会使用自己默认的字符集
注:mysqld.exe默认的字符集是安装数据库时指定的,与创建数据库和数据表时指定的字符集无关。通过 show variables like 'character_set%'; 查看
4、解决方案:mysql.exe客户端在进行数据操作之前将自己所使用的字符集告诉mysqld.exe(cmd下的mysql.exe默认都只有一个字符集:GBK)
5、客户端向服务器插入中文数据没有成功,是因为在当前编码(字符集)下,对应的二进制编码转换成的十六进制是:一个汉字 <--> 两个字节(GBK)。而服务器认为接收数据的字符集是UTF8:一个汉字 <--> 三个字节,转换失败
注:GBK是两个字节读一次,UTF8是三个字节读一次
6、数据库服务器表现的一些特性,都是通过服务器端的变量来保存。系统先读取自己的变量,然后决定应该怎么表现
7、查看服务器识别的字符集
-- 查看服务器识别的字符集
show character set;
(1)服务器一共支持39种字符集
(2)基本上,服务器是万能的,什么字符集都支持
8、查看服务器默认的对外处理的字符集
-- 查看服务器默认的对外处理的字符集
show variables like 'character_set%';
9、服务器默认的接收客户端数据的字符集是utf8(安装数据库时指定的)
10、问题根源:客户端数据的字符集只能是GBK,而服务器接收客户端数据时,认为其字符集是utf8,产生矛盾
11、解决方案:改变服务器默认的接收客户端数据的字符集为GBK(客户端的不能改,所以只能修改服务器的字符集)
-- 设置服务器默认的接收客户端数据的字符集
set character_set_client = 字符集;
-- 改变服务器默认的接收客户端数据的字符集为GBK
set character_set_client = GBK;
12、插入中文数据成功,但使用select查看数据时依旧乱码
注:只设置character_set_client,就可以插入数据(告诉服务端,客户端传入的数据是gbk,服务器就会自动去处理了)。但只设置character_set_client,查询时会出现乱码
13、原因:返回时,数据来源是服务器,解析数据是客户端。客户端只识别GBK(一个汉字 <--> 两个字节),但服务器返回给客户端的数据是utf8(一个汉字 <--> 三个字节),客户端解析不了,导致显示时乱码
14、解决方案:修改服务器返回给客户端的数据的字符集为GBK
-- 设置服务器返回给客户端的数据的字符集
set character_set_results = 字符集;
-- 修改服务器返回给客户端的数据的字符集为GBK
set character_set_results = GBK;
15、set 变量 = 值; 的这种修改是会话级别的。即 当前客户端、当次连接有效,关闭失效
16、设置服务器对客户端的字符集,可以使用快捷方式:set names 字符集;
-- 设置服务器对客户端的字符集的快捷方式
set names 字符集;
-- 等效于
set character_set_client = 字符集;
set character_set_results = 字符集;
set character_set_connection = 字符集; -- 连接层字符集
注:connection连接层,只是为了更方便客户端与服务端进行字符集转换而设,是字符集转变的中间者。如果统一了效率会更高,不统一也没问题
17、mysql.exe与mysqld.exe之间的处理关系一共分为三层
(1)客户端传入数据给服务端(client):character_set_client -- 为了让服务器识别客户端传来的数据
(2)服务端返回数据给客户端(server):character_set_results(服务端返回的数据是结果results) -- 为了告诉客户端服务端返回的数据的字符集
(3)客户端与服务端之间的连接(connection):character_set_connection -- 更好的帮助客户端与服务端之间进行字符集转换
18、客户端的数据是gbk,服务器针对客户端(接收和发送)默认是utf8,服务器需要做转换。相当于:
(1)客户端向服务器插入数据时,需要指定字符集
(2)服务器返回给客户端数据时,也需要指定字符集
但服务器支持39种字符集,服务器想以怎样的字符集存储,不关客户端的事儿。我们在乎的是客户端给服务器数据时,服务器是否认识;服务器将数据返回给客户端时,客户端是否认识(客户端与服务端之间的通信,必须要通过一个统一的字符集才能保证彼此之间对于数据的识别)
二、校对集
1、校对集:数据比较的方式(数据中有一个对应的集合,按照某种指定的方式比较)
2、校对集较少使用,一般情况下默认不区分大小写(默认使用_ci)
3、校对集有三种格式
(1)_bin:binary,二进制比较。取出二进制位,一位一位的比较。区分大小写
(2)_cs:case sensitive,大小写敏感。区分大小写(较少使用)
(3)_ci:case insensitive,大小写不敏感。不区分大小写(默认使用_ci)
4、查看数据库所支持的校对集
-- 查看数据库所支持的校对集
show collation;
注:utf8不支持中文比较,gbk支持中文比较(gbk_chinese_ci)
5、校对集应用:只有当数据产生比较的时候,校对集才会生效
6、每个数据库都有自己的校对集,在.opt文件中(保存数据的文件夹data --> 对应数据库名字的文件夹 --> .opt文件),里面保存了库选项(字符集和校对集)
-- .opt文件中的内容
default-character-set=gbk
default-collation=gbk_chinese_ci -- 默认为_ci,不区分大小写
7、对比:使用utf8的_bin和_ci来验证不同的校对集的效果(utf8不支持_cs)
(1)创建不同校对集对应的表
-- 使用不同的校对集创建表
create table my_collate_bin(
name char(1)
)charset utf8 collate utf8_bin;
create table my_collate_ci(
name char(1)
)charset utf8 collate utf8_general_ci;
(2)插入数据
-- 插入数据
insert into my_collate_bin values ('a'), ('A'), ('B'), ('b');
insert into my_collate_ci values ('a'), ('A'), ('B'), ('b');
-- 查看(结果是插入的顺序)
select * from my_collate_bin; -- 结果:a A B b
select * from my_collate_ci; -- 结果:a A B b
(3)比较。根据某个字段进行排序(order by)
-- 根据某个字段进行排序:order by 字段名 [asc|desc]
-- asc:升序,desc:降序。默认是升序asc
-- 排序查找
-- 区分大小写排序。结果:A B a b
select * from my_collate_bin order by name;
-- 不区分大小写排序。结果:a A B b
select * from my_collate_ci order by name;
8、校对集必须在没有数据之前声明好。如果有了数据,再进行校对集的修改,则修改无效
9、修改校对集
-- 修改表选项(字符集、校对集、存储引擎)
alter table 表名 表选项 [=] 值;
-- 修改校对集
-- 修改校对集前,首先要确保表中数据为空,否则修改无效
alter table my_collate_ci collate=utf8_bin;
alter table my_collate_ci collate=utf8_general_ci;
10、字符集与其默认对应的校对集
(1)字符集:gbk,校对集:gbk_chinese_ci
(2)字符集:utf8,校对集:utf8_general_ci
三、乱码问题
1、动态网站由三部分构成:浏览器、Apache服务器、数据库服务器。三个部分都有自己的字符集(中文),数据需要在三个部分之间来回传递,很容易产生乱码
2、如何解决乱码问题:统一编码(三码合一)。但我们只能控制服务器(Apache服务器和数据库服务器),浏览器是用户管理的,控制不了