字符集与比较规则

152 阅读6分钟

简介

为什么要有字符集

计算机中实际存储的是二进制数据,那它是怎么存储字符的呢?当然是建立了映射关系(字符集就是做这个的),要建立关系,需要明确两个事情:

  1. 要把哪些字符映射成二进制数据?界定数据范围
  2. 怎么映射?将字符映射成二进制数据的过程叫做编码,将二进制数据映射成为字符的叫做解码

比较规则是干什么的

两个字符如何进行比较呢?可能是直接映射成二进制编码来进行比较(比如:ASCII编码),但是可能在有些情况下,需要忽略大小写进行比较,比如 a 和 A 当作一个字符来看(说明采用同一种字符集的数据可能存在多样的比较规则

常见字符集

同一个字符使用不同的字符集进行编码时,所表现的形式也不一样,如:存储字符'我',UTF8(3字节),GBK(2字节)

  1. ASCII:共收录 128 个字符,包括空格、标点符号、数字、大小写字母和一些特殊字符
  2. GB2312:可以表示大部分汉字(6763个),兼容ASCII字符集,是一种变长编码方式(如果某个字节是在0-127之间的(该字节的最高位是0),就意味着是一个字符,就用一个字节表示;否则(该字节的最高位是1)就是两个字节表示一个字符
  3. GBK:对 GB2313 的扩充
  4. Unicode:最常用字符集,基本包含了所有的字符,包括 UTF8(1-4字节)、UTF16(2或4字节)、UTF32(4字节),也属于变长编码

MySQL 中支持的字符集和比较规则

MySQL中的 utf8 与 utf8mb4

utf8 在 MySQL 中指的是 utf8mb3,使用 1-3 字节表示字符;utf8mb4 才是完整版的 utf8,1-4字节,字符集表示一个字符所用的最大字节长度在某些方面会影响系统的存储和性能,MySQL 8.0 对 utf8mb4 进行了优化,已经是默认的字符集了

字符集的查看

show charset [like 字符集]

只截图了部分内容:default collation:表示这种字符的默认比较规则 image.png MaxLen 表示的是这种字符集最多需要几个字节表示一个字符,以下列举常用的,需要记住:

image.png

比较规则的查看

show collation [like 比较规则]

image.png

解释: 字符集打头,然后中间的是属于哪一种语言的比较规则,general 表示通用,最后是是否区分重音、大小写等

image.png

字符集和比较规则的应用

各级别的的字符集和比较规则

分为四个级别:服务器级别、数据库级别、表级别、列级别

服务器级别

系统变量描述
character_set_server服务器级别的字符集
collation_server服务器级别的比较规则

默认字符集 utf8,比较规则 utf8_general_ci,可以通过配置文件或set语句进行设置

数据库级别

系统变量描述
character_set_database数据库级别的字符集
collation_database数据库级别的比较规则
-- 1. create 时指定
-- 2. alter 关键字进行修改
3. show variables like "character_set_databases"   查看当前数据库的字符集
4. show variables like "collation_database"   查看当前数据库的比较规则

-- 不能通过 set 进行修改这两个变量,如果没有指定,就是用服务器的

表级别

-- 1. create 时指定
-- 2. alter 关键字进行修改
查看建表语句,即可看到当前表的比较规则和字符集,desc 关键字

-- 如果没有指定,就是用数据库的,以此类推

列级别

-- 1. create 时指定
-- 2. alter 关键字进行修改
查看建表语句,即可看到当前列的比较规则和字符集,desc 关键字

-- 如果没有指定,就是用当前表的,以此类推

注意:如果在表中已经存储了数据,当修改后的列级别字符集不能存储当前有的数据时,就会报错

进修改字符集或比较规则

  1. 只修改字符集:比较规则就会变成字符集默认的比较规则
  2. 只修改比较规则:字符集会变成比较规则对应的字符集

客户端和服务器通信过程中使用的字符集

下面的字符集都是针对我们在 SQL 语句中直接输入字符的时候【比如下面:tt 是列,'a' 就是字符,都是针对 'a' 进行一系列的转换的】

select tt = 'a';

客户端发送请求

如果在启动客户端时没有指定字符集,那么客户端包装数据就是采用操作系统的字符集进行包装传输【使用 cmd 黑框框启动】;如果使用的是mysql自带的黑框框客户端,则会读配置文件;如果时第三方客户端的话,也会有自己的一套规则
mysql --default-character-set=utf8 进行指定

服务器接收请求

首先,服务器会去查看系统变量 character-set-client,服务器就是根据这个值对应的字符集来进行解析当前客户端的传过来的字节系列的,该变量是 session 级别的

服务器处理请求

在上述接收到了请求后,服务器会将数据转成character-set-connection变量内部值对应的字符集,采用该字符集的比较规则来进行比较 当我们进行条件筛选的时候,如果列级别的字符集是 utf8,而 character-set-connection 的值是 gbk 的话,这时 列级别规则优先,需要把使用了 character-set-connection 内部的字符集转换的值再次转换为 列级别的规则

服务器响应请求

将最终的结果转换为 character-set-results内部的字符集来进行编码返回,也属于 session 级别的

上述的过程主要针对三个系统变量来进行操作的,他们都属于 session 级别的

  1. character-set-client:服务器解析客户端请求的字符集
  2. character-set-connection:服务器内部处理数据时的字符集
  3. character-set-results:服务器最终返回数据时的字符集

在客户端发送请求时,每个客户端其实都维护着一个默认字符集【客户端会根据操作系统的字符集来映射一个MySQL客户端支持的字符集】,如果映射不成功的话,则会使用MySQL默认的字符集【5.7:latin1,8.0:utf8mb4】

客户端接收请求

与发送请求对应,没有指定就使用操作系统映射的那个,指定了的话就使用自己的