3.1 简介

字符集简介

字符与二进制数据的映射关系。

将字符映射成二进制数据的过程叫作**==编码==,将二进制数据映射到字符的过程叫作==解码==**。

人们抽象出的概念,==字符集==:描述某个字符范围的编码规则。

比较规则简介

直接用字符对应的二进制比较大小的比较规则叫**==二进制比较规则==**,这种规则比较简单。

同一种字符集可以有多种比较规则。

一些重要的字符集

  • ASCII字符集。128个字符。(一个字节编码一个字符)

  • ISO 8859-1字符集(Latin1)。256个字符(在ASCII基础扩充了128个西欧常用字符)。(一个字节)

  • GB2312字符集。6762个汉字+682个其它。对应ASCII字符的一个字节编码,其它两个字节编码。(变长编码方式

    计算机读取一个字节序列时,怎么区分某个字节代表的是一个单独的字符还是某个字符的一部分呢?

    ASCII的最高位默认为0,如果为1就是两个字节代表一个单独的字符。

  • GBK字符集。对GB2312的扩充。

  • UTF-8字符集。几乎收录世界各国使用的字符,而且还在不断扩充。1~4个字节编码一个字符。

    UTF-8只是Unicode字符集的一中编码方案,其它有UTF-16(2或4字节编码)、UTF-32(4字节编码)。

    UTF-8采用1~4个字节编码一个字符;

    UTF-16采用2或4个字节编码一个字符;

    UTF-32采用4个字节编码一个字符。

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

MySQL中的utf8和utf8mb4

  • Utf8mb3(简称utf8):阉割过的UTF-8字符集,只使用1~3字节表示一个字符。

    UTF-8:8-bit Unicode Transformation Format

    mb3: maximun of 3 bytes per multibyte character

  • utf8mb4:正宗的UTF-8字符集,1~4个字节。MySQL8.0已经优化,默认字符集。

字符集的查看

1
2
3
4
5
-- `Character Set`和`Charset`是同义词
Show (Character Set | Charset) [Like 匹配的模式];

SHOW CHARACTER SET LIKE 'utf8%';
SHOW CHARSET;

MySQL中表示字符集的名称时使用小写形式。

大概有41中字符集。

比较规则的查看

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Show Collation [Like 匹配的模式];

show Collation Like 'utf8%';
+--------------------------+---------+-----+---------+----------+---------+---------------+
| Collation                | Charset | Id  | Default | Compiled | Sortlen | Pad_attribute |
+--------------------------+---------+-----+---------+----------+---------+---------------+
| utf8_bin                 | utf8    |  83 |         | Yes      |       1 | PAD SPACE     |
| utf8_croatian_ci         | utf8    | 213 |         | Yes      |       8 | PAD SPACE     |
| utf8_czech_ci            | utf8    | 202 |         | Yes      |       8 | PAD SPACE     |
| utf8_danish_ci           | utf8    | 203 |         | Yes      |       8 | PAD SPACE     |
...
  • 比较规则的名称以其关联的字符集名称开头。
  • 中间紧跟着该比较规则所应用的语言。如,utf8_polish_ci表示波兰语的比较规则…,utf8_general_ci是通用的比较规则。
  • 名称后缀表示该比较规则是否区分语言中的重音、大小写等。

3.3 字符集和比较规则的应用

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

1.服务器级别

服务器级别的字符集和比较规则的系统变量:character_set_server, collation_server

1
2
SHOW VARIABLES LIKE 'character_set_server';
SHOW VARIABLES LIKE 'collation_server';
2.数据库级别

在创建和修改数据库时可以指定,具体语法:

1
2
3
4
5
6
7
Create Database 数据库名
	[[Default] Character set 字符集名称]
	[[Default] Collate 比较规则名称];
	
Alter Database 数据库名
	[[Default] Character set 字符集名称]
	[[Default] Collate 比较规则名称];
1
2
3
Create Database charset_demo_db
Character Set gb2312
Collate gb2312_chinese_ci;

对应的系统变量:character_set_database, collation_database(不能通过这两个变量来修改数据库的字符集和比较规则)。

查看当前数据库的字符集和比较规则:

1
2
SHOW VARIABLES LIKE 'character_set_database';
SHOW VARIABLES LIKE 'collation_database';

创建数据库时不指定字符集和比较规则,就使用服务器级别的。

3.表级别

也可在创建和修改表时指定,具体语法:

1
2
3
4
5
6
7
Create Table 表名(列的信息)
	[[Default] Character set 字符集名称]
	[Collate 比较规则名称];
	
Alter Table 表名
	[[Default] Character set 字符集名称]
	[Collate 比较规则名称];
1
2
3
Create Table t (
	col Varchar(10)
) character Set utf8 collate utf8_general_ci;

同样创建表示没指定,就使用数据库级别的。

4.列级别

对于存储字符串的列,同一个表中不同的列也可以有不同的字符集和比较规则

1
2
3
4
5
6
Create Table 表名(
	列名 字符串类型 [Character set 字符集名称] [Collate 比较规则名称],
  ...
);

Alter Table 表名 Modify 列名 字符串类型 [Character set 字符集名称] [Collate 比较规则名称];

对于某个列来说,如果在创建和修改表的语句中没有指明其字符集和比较规则,则使用表的。

5.仅修改字符集或仅修改比较规则
  • 只修改字符集,则比较规则将变为修改后的字符集默认的比较规则;
  • 只修改比较规则,则字符集将变为修改后的比较规则对应的字符集。
6.各级别字符集和比较规则小结
  • 如果创建或修改列时没有显式指定字符集和比较规则,则该列默认使用表的宇符集和比较规则;
  • 如果创建表时没有显式指定字符集和比较规则,则该表默认使用数据库的字符集和比较规则;
  • 如果创建数据库时没有显式指定字符集和比较规则,则该数据库默认使用服务器的字符集和比较规则。

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

1.编码和解码使用的字符集不一致

在UTF-8字符集编码下的字节序列是0xE68891。如果程序A把这个字节序列发送到程序B,程序B使用不同的字符集解码(假设使用GBK),过程如下:(可通过在线工具 汉字字符集编码查询 测试)

a. 首先看第一个字节0xE6,大于0x7F(十进制127),说明待读取字符是两字节编码。继续读一字节后得到 OxE688,然后从 GBK 编码表中查找字节为 0xE688 对应的字符,发现是字符。 b. 继续读一个字节 0x91,它的值也大于 0x7F,试图再读一个字节时发现后边没有了,所以这是半个字符。 c. 最终,0xE68891被 GBK 字符集解释成一个字符’鎴’和半个字符。

2.字符集转换

如果接受0xE68891这个字节序列的程序按照UTF-8字符集解码(得到二进制序列为111001101000100010010001);然后再按照GBK字符集进行编码,编码后的字节序列为0xCED2。这个过程就叫作**==字符集转换==**。

3.MySQL中的字符集转换过程🔖

从机器的角度看,客户端发送的请求以及服务器返回的响应本质上就是一个字节序列

在这个“客户端发送请求,服务器返回响应”的过程中,其实经历了多次的字符集转换

客户端发送请求

一般,客户端编码请求字符串时使用的字符集与操作系统当前的字符集一致。

  • 类UNIX系统时

系统当前使用的字符集,由三个环境变量决定:LC_ALLLC_CTYPELANG(优先级渐渐降低)。

  • Windows

代码页(code page)

服务器接受请求

服务器将客户端请求的字符序列看作是使用系统变量character_set_client代表的字符集进行编码的字节序列(每个客户端与服务器建立连接后,服务器都会为其维护一个单独的SESSION级别的character_set_client变量)。

服务器处理请求
服务器生成响应

character_set_client、character_set_connection 和character_set_results

这三个系统变量作用范围都是Session级别。

如果MySQL不支持操作系统当前使用的字符集,则会将客户端默认的字符集设置为MySQL的默认字符集(5.7前是latin1,8.0之后改为utf8mb4)。

客户端接收到响应

3️⃣比较规则的应用

比较规则通常用来==比较字符串的大小以及对某些字符进行排序==,所以也称为排序规则

1
Insert Into t(col) Values('a'), ('b'), ('A'), ('B'), ('我');
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
-- 默认gbk_chinese_ci不区分大小写
mysql> Select * From t Order By col;
+------+
| col  |
+------+
| a    |
| A    |
| b    |
| B    |
|    |
+------+
5 rows in set (0.00 sec)


-- gbk_bin是比较字符的二进制编码,所以区分大小写
mysql> Alter Table t Modify col Varchar(10) Collate gbk_bin;
Query OK, 5 rows affected (0.02 sec)
Records: 5  Duplicates: 0  Warnings: 0

mysql> Select * From t Order By col;
+------+
| col  |
+------+
| A    |
| B    |
| a    |
| b    |
|    |
+------+
5 rows in set (0.00 sec)