1.6 字符集的设置
在MySQL 8.0以前的版本中,默认字符集为latin1。开发人员在进行数据库设计的时候,往往会将默认字符集修改为utf8,这时utf8指向的是utf8mb3。如果开发人员忘记修改默认字符集,就会出现乱码问题。从MySQL 8.0开始,默认字符集改为utf8mb4,从而避免了乱码问题。
1.6.1 查看字符集
使用如下SQL语句查看MySQL 8.0中的字符集。其中,Charset列表示字符集名称,Default collation列表示字符集的默认校对规则(参见1.6.2节),Maxlen列表示该字符集中的一个字符最多需要使用多少字节表示。
也可以在上述SQL语句中加入WHERE或LIKE条件。例如,要查看与“utf”相关的字符集,则可以使用如下SQL语句。
MySQL中常用的字符集是utf8。从上述结果中可以看到,utf8字符集有两个,分别是utf8和utf8mb4。其中,utf8字符集中的一个字符最多需要使用3字节表示,utf8mb4字符集中的一个字符最多需要使用4字节表示。
在MySQL中,utf8是utf8mb3的别名,因此,后面提到utf8就意味着一个字符最多需要使用3字节表示。在一般情况下,使用utf8字符集就足够了,但是部分特殊字符需要使用4字节才能表示,这时候就需要使用utf8mb4字符集。我们可以把utf8mb4理解为utf8的超集。
1.6.2 查看校对规则
校对(Collation)规则是在字符集内用于字符比较和排序的一套规则。例如,有的校对规则区分字母大小写,有的校对规则无视字母大小写。
可以使用如下SQL语句查看MySQL支持的校对规则(限于篇幅,只展示部分结果)。
校对规则名称里面包含该校对规则主要作用于哪种语言,例如,utf8_polish_ci表示该校对规则主要作用于波兰语,utf8_spanish_ci表示该校对规则主要作用于西班牙语,utf8_general_ci是一种通用的校对规则。校对规则名称后缀表示该校对规则是否区分语言中的重音、字母大小写等,具体如表1-3所示。
表1-3 校对规则名称后缀的含义
下面在MySQL 8.0的数据库chapter1中创建表test1,并向表中插入数据,如下所示。
首先查询表test1中所有的数据,然后查询name='a'的数据,结果如下所示。
从上述结果中可以看到,当查询字符为'a'的时候,结果中有两条数据。在没有显式指定校对规则的情况下,可以使用如下语句查看表test1的校对规则,可以看到表test1的校对规则为utf8mb4_0900_ai_ci,后缀_ci表示不区分字母大小写。
使用如下语句创建表test2,并向表中插入两条数据,指定校对规则为utf8mb4_0900_as_cs,后缀_cs表示区分字母大小写。
执行如下语句,可以发现,当查询字符为'a'的时候,结果中只有一条数据。
1.6.3 各级别的字符集和校对规则
前面介绍了MySQL中的字符集和校对规则,有的作用于数据库上,有的作用于表上。其实,MySQL中的字符集和校对规则有4个级别的默认设置,分别是服务器级别、数据库级别、表级别、列级别。下面展开讲解各个级别的具体含义。
1.服务器级别
系统变量character_set_server和collation_server分别表示服务器级别的字符集和校对规则。服务器级别的默认字符集为utf8mb4,默认校对规则为utf8mb4_0900_ai_ci。如果仅指定字符集而不指定校对规则,那么校对规则为该字符集对应的默认校对规则。修改服务器级别的字符集有3种方式。
(1)修改my.cnf配置文件,如下所示,服务器启动后开始生效。
(2)在启动服务器端程序时,通过启动选项来指定服务器级别的字符集和校对规则,如下所示。
(3)在服务器端程序运行过程中,使用SET语句修改字符集和校对规则,如下所示。这种方式的修改是临时性的,关闭命令行窗口就会失效。
2.数据库级别
系统变量character_set_database和collation_database分别表示数据库级别的字符集和校对规则。要查看给定数据库的默认字符集和校对规则,请使用如下语句。
在创建和修改数据库的时候,可以指定该数据库的字符集和校对规则,语法如下所示。
其中,[DEFAULT]CHARACTER SET用于指定数据库的字符集,[DEFAULT]COLLATE用于指定数据库的校对规则。DEFAULT可以省略,不影响语句的含义。
例如,创建数据库chapter1_character_demo,指定字符集为utf32,指定校对规则为utf32_general_ci,语句如下所示。
可以使用如下语句修改已经创建的数据库的字符集。
MySQL根据下面的规则选择数据库的字符集和校对规则。
(1)如果创建和修改数据库的语句中同时指定了字符集和校对规则,那么该数据库会使用指定的字符集和校对规则。
(2)如果创建和修改数据库的语句中只指定了字符集,没有指定校对规则,那么该数据库会使用该字符集对应的默认校对规则。
(3)如果创建和修改数据库的语句中只指定了校对规则,没有指定字符集,那么该数据库会使用该校对规则对应的字符集。
(4)如果创建和修改数据库的语句中没有指定字符集和校对规则,那么该数据库会使用服务器级别的字符集和校对规则。
3.表级别
在创建和修改表的时候,可以指定表的字符集和校对规则,语法如下所示。
例如,在刚刚创建的chapter1_character_demo数据库中创建表test1,并指定该表的字符集和校对规则,语句如下所示。
MySQL根据下面的规则选择表的字符集和校对规则。
(1)如果创建和修改表的语句中同时指定了字符集和校对规则,那么该表会使用指定的字符集和校对规则。
(2)如果创建和修改表的语句中只指定了字符集,没有指定校对规则,那么该表会使用该字符集对应的默认校对规则。
(3)如果创建和修改表的语句中只指定了校对规则,没有指定字符集,那么该表会使用该校对规则对应的字符集。
(4)如果创建和修改表的语句中没有指定字符集和校对规则,那么该表会使用其所在数据库的字符集和校对规则。
4.列级别
对于存储字符串的列,同一张表中的不同列也可以有不同的字符集和校对规则。在创建和修改列定义的时候,可以指定该列的字符集和校对规则,语法如下所示。
使用如下语句修改表test1中col列的字符集和校对规则。
MySQL根据下面的规则选择列的字符集和校对规则。
(1)如果创建和修改列定义的语句中同时指定了字符集和校对规则,那么该列会使用指定的字符集和校对规则。
(2)如果创建和修改列定义的语句中只指定了字符集,没有指定校对规则,那么该列会使用该字符集对应的默认校对规则。
(3)如果创建和修改列定义的语句中只指定了校对规则,没有指定字符集,那么该列会使用该校对规则对应的字符集。
(4)如果创建和修改列定义的语句中没有指定字符集和校对规则,那么该列会使用其所在表的字符集和校对规则。
知道了这些规则后,对于给定的表,我们应该知道其中各列的字符集和校对规则是什么,从而根据该列的数据类型来确定存储数据时每列中的实际数据占用的存储空间大小。
1.6.4 MySQL 5.7和MySQL 8.0中数据库级别默认字符集的变化
MySQL 5.7中数据库级别的默认字符集为latin1,该字符集不支持中文,保存中文数据时会报错。
在MySQL 5.7中创建数据库chapter1,在其中创建表test3,插入非中文数据时不报错,插入中文数据时报错,如下所示。
这是因为,在默认情况下,创建表时使用的是latin1字符集。查看表结构,结果如下所示。
想要修改已经创建的表的字符集,使用如下语句即可。
再次插入中文数据,结果如下所示,可以发现插入成功。
但是,如果原有数据是用非utf8字符集编码的,那么数据本身的编码不会发生改变。对于这类数据,需要先将其导出或删除,再重新插入。
MySQL 8.0中数据库级别的默认字符集为utf8mb4。在MySQL 8.0中同样创建数据库chapter1和表test3,可以直接插入中文数据,这里不再演示。