字符集和比较规则
什么是字符集?
在计算机底层,所有的数据都是由二进制模型构成,当然也是包括了字符串。
- 从字节流到字符串的映射过程叫做解码
- 从字符串到字节流的映射过程叫做编码
无论是编码还是解码,都要遵守一套准则,落实到书面上,就是我们口中的码表
。
所谓的字符集就是在某种映射规则范围内的字符集合。
超过了集合范围的映射会出现字符乱码现象,比如一些“鬼符”。
产生乱码的原因也很简单:编码与解码没有使用同一套字符集,即同一套码表。
什么是比较规则?
字符串不像数字,数学上有明确的定义大小的比较。但是有些时候,我们需要字符串按照某种方式进行排列,这个时候就需要定义一套比较逻辑,这就是比较规则。
所谓的比较规则实际上是就是给不同的字符串赋权重值,然后这些字符串按照权重值进行顺序排列。
一些重要的字符集
ASCII 字符集
最基本的字符集,收录了
128
个字符的映射关系。其他所有的字符集都是在此基础上发展的,即所有的字符集都兼容ASCII 字符集
。GB 2321 字符集 和 GBK 字符集
后者是对前者的扩充,咱中国的,当然也收录了其他国家的一些文字。
UTF-8 字符集
其实是 Unicode 字符集的一种
编码方案
,可以理解为一种实现。Unicode 也叫做万国码,几乎收录了全球所有的字符。UTF-8 作为它的一种实现方式,是一种可变长的字符集,单个字符所占的大小在1~4
个字节。什么是
可变长
的字符集?A 给 B 发送消息,只是纯英文,那么很显然,一个字节大小完全可以表示消息的所有字符。那如果消息中带有中文,那么可能就需要
2~4
个字节表示所有的字符。不同编码范围的字符所占用的空间大小是不一样的。
MySQL 中的 utf8 和 utf8mb4
utf8mb3
指的就是
utf8
,使用1~3
个字节表示单个字符,可以理解为阉割版的UTF-8
字符集utf8mb4
完整意义上的
UTF-8
字符集,收录了很多emoji
表情
MySQL 5.7 默认的字符集是latin1
。MySQL 8.0 中,已经对utf8mb4
做了很大程度上的优化,也将utf8mb4
作为默认字符集。
MySQL 中的比较规则
不同的字符集对应着很多套比较规则,一般比较规则的格式如下:
utf8_general_ci
,general
表示这是一个通用的比较规则,ci
表示不区分大小写,一般我们都使用通用的比较规则,也是默认的。
有些语言区分什么重音
和轻音
或者其他什么的,这些我们一般遇不到。
重点关注两个结尾的_ci
和_cs
:
前者不区分大小写,后者区分。MySQL 默认字符串的比较不区分字符大小写。
字符集和比较规则的应用
我们可以设置不同级别的字符集和比较规则:
服务器级别
启动参数设置或者配置文件中修改。
数据库级别
创建时可以指定,创建后可以修改
表级别
创建时可以指定,创建后可以修改
字段级别
创建时可以指定,创建后可以修改,一般没必要
仅修改字符集或仅修改比较规则
先说结论:一方的修改,都会对另一方造成影响。
- 如果修改了字符集,没有指定比较规则,默认就是属于该字符集通用的比较规则
- 如果修改了比较规则,也会连带修改字符集
(本质上来说,字符集和比较规则是相互匹配的,总不能utf8
的字符集使用gbk
的某一套比较规则吧?)
字符集在 MySQL 客户端与服务端之间的转换
如果通信双方使用不一样的字符集进行编码和解码,那么就会出现乱码。
为了避免乱码,还有考虑到字符集之间转换的消耗,我们鼓励客户端与服务端之间使用同一套字符集。
很显然,对于客户端而言,我们是不可控的,这要求有点高了,而且服务端采用的字符集客户端不一定支持,反之亦然。所以,才有了字符集转换一说。
我们从客户端请求到服务端响应说起:
客户端请求
客户端在于服务端建立连接的时候,会将自己所使用的字符集信息发送给服务端,由服务端进行会话存储。通常是系统默认的字符集,当然也可以自行指定。
服务端响应
连接建立完成后,服务端接收到客户端发来的消息,会先按照客户端的字符集进行解码,然后再根据自身的字符集进行编码,执行完相关操作后,返回结果。
在返回结果之前,也会对结果进行字符集的转换,转换之后再响应给客户端。
这套字符集转换机制,对客户端来说是友好的,客户端做的事很少。但这里面会出现一个问题,那就是如果服务端不支持客户端的字符集(通常是由于服务端系统中没有这套字符集),就有可能出现乱码或者根本连接不上这种情况。当然,现在来说的话,除非是有意而为之,否则基本不可能出现。
总结
看似是谁都知道的基础知识,实际上也是藏着很多的细节。
2025/01/26
writeBy kaiven