纯文本在计算机底层会转换为二进制保存,将字符转换为二进制码的过程,称为编码,将二进制码转换为字符的过程,称为解码。
字符集
编码和解码时所采用的规则,称为字符集。常见字符集有:ASCII、GBK、Unicode等。编写程序时,如果发现程序代码出现乱码的情况,就要马上去检查字符集是否正确。
- ASCII字符集
共收录128个字符,包括空格、标点符号、数字、大小写字母和一些不可见字符。由于总共才128个字符,所以可使用1个字节来进行编码。 - ISO 8859-1字符集
共收录256个字符,是在ASCII字符集基础上又扩充了128个西欧常用字符,也可以使用1个字节来进行编码。这个字符集也有一个别名latin1。 - GB2312字符集
收录了汉字以及拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母,其中收录汉字6763个,其他文字符号682个。同时这种字符集又兼容ASCII字符集,所以在编码方式上显得有些奇怪:如果该字符在ASCII字符集中,则采用1字节编码,否则采用2字节编码。这种表示一个字符需要字节数可能不同的编码方式称为变长编码方式。如果某个字节是在0~127之内的,就意味着一个字节代表一个单独字符,否则就是两个字节代表一个单独字符。 - GBK字符集
该字符集只是在收录字符范围上对GB2312字符集作了扩充,编码方式上兼容GB2312,包含了2万多个汉字等字符。 Unicode字符集
收录地球上能想到的所有字符,而且还在不断扩充,这种字符集兼容ASCII字符集。Unicode字符集采用UTF-8、UTF-16、UTF-32这几种编码方案,UTF-8使用1~4个字节编码一个字符,UTF-16使用2个或4个字节编码一个字符,UTF-32使用4个字节编码一个字符。- UTF-8是Unicode字符集的一种编码方案,采用变长编码方式,编码一个字符需要使用1~4个字节。英文、数字等只占1个字节,汉字占用3个字节。
UTF-8编码方式(二进制) | |
---|---|
0xxxxxxx(ASCII码) | 1个字节 |
110xxxxx 10xxxxxx | 2个字节 |
1110xxxx 10xxxxxx 10xxxxxx | 3个字节 |
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx | 4个字节 |
MySQL支持字符集
MySQL自己定义了两个概念:
- utf8mb3:阉割过的utf8字符集,只使用1~3个字节表示字符
- utf8mb4:正宗的utf8字符集,使用1~4个字节表示字符
在MySQL中utf8是utf8mb3的别名,这就意味着使用1~3个字节来表示一个字符,如果想使用4字节编码一个字符,比如存储一些emoji表情啥的,那请使用utf8mb4。
查看字符集:SHOW (CHARACTER SET|CHARSET) [LIKE 匹配的模式];
校对规则
查看命令:SHOW COLLATION [LIKE 匹配的模式];,一种字符集可能对应着若干种校对规则(排序规则)。
后缀 | 英文释义 | 描述 |
---|---|---|
_ai | accent insensitive | 不区分重音 |
_as | accent sensitive | 区分重音 |
_ci | case insensitive | 不区分大小写 |
_cs | case sensitive | 区分大小写 |
_bin | binary | 以二进制方式比较 |
每种字符集都有一种默认的比较规则,比方说utf8
字符集默认的比较规则就是utf8_general_ci
。由于字符集和比较规则是互相有联系的,如果只修改了字符集,比较规则也会跟着变化,如果只修改了比较规则,字符集也会跟着变化。
MySQL有4个级别的字符集和比较规则,分别是:
- 服务器级别
- 数据库级别
- 表级别
- 列级别
服务器级别
MySQL提供了两个系统变量来表示服务器级别的字符集和比较规则:
系统变量 | 描述 |
---|---|
character_set_server | 服务器级别的字符集 |
collation_server | 服务器级别的比较规则 |
数据库级别
在创建和修改数据库时可指定该数据库的字符集和比较规则,具体语法如下:
CREATE DATABASE 数据库名
[[DEFAULT] CHARACTER SET 字符集名称]
[[DEFAULT] COLLATE 比较规则名称];
ALTER DATABASE 数据库名
[[DEFAULT] CHARACTER SET 字符集名称]
[[DEFAULT] COLLATE 比较规则名称];
如果创建数据库时不指定字符集和比较规则,则使用服务器级别的字符集和比较规则作为数据库的字符集和比较规则。
查看当前数据库使用的字符集和比较规则,可以查看下面两个系统变量的值(只读),前提是使用USE
语句选择当前默认数据库,如果没有默认数据库,则变量与相应服务器级系统变量具有相同的值:
系统变量 | 描述 |
---|---|
character_set_database | 当前数据库的字符集 |
collation_database | 当前数据库的比较规则 |
表级别
也可以在创建和修改表的时候指定表的字符集和比较规则,如果没有指明字符集和比较规则,将使用该表所在数据库的字符集和比较规则作为该表的字符集和比较规则。
列级别
对于存储字符串的列,同一个表中不同列也可以有不同的字符集和比较规则,如果没有指明字符集和比较规则,将使用该列所在表的字符集和比较规则作为该列的字符集和比较规则。
字符集转换
客户端从发送请求到返回结果这个过程中伴随着多次字符集的转换,在这个过程中会用到3个系统变量:
系统变量 | 描述 |
---|---|
character_set_client | 服务器解码请求时使用的字符集 |
character_set_connection | 服务器处理请求时会把请求字符串从character_set_client转为character_set_connection |
character_set_results | 服务器向客户端返回数据时使用的字符集 |
通常把这三个系统变量设置成和客户端使用的字符集一致,这样减少了很多无谓的字符集转换。为了方便我们设置,MySQL提供了一条非常简便的语句:SET NAMES 字符集名;。
如果想在启动客户端时就把这三个系统变量的值设置成一样的,可指定一个叫default-character-set
的启动选项,比如在配置文件里可以这么写:
[client]
default-character-set=utf8
它起到的效果和执行一遍SET NAMES utf8;
是一样一样的,都会将那三个系统变量的值设置成utf8。