1、MySQL 字符集简介
1.1 字符集简介
MySQL 服务器可以支持多种字符集,在同一台服务器、同一个数据库甚至同一个表的不同字段都可以指定使用不同的字符集,相比 Oracle 等其他数据库管理系统,在同一个数据库只能使用相同的字符集,MySQL 明显存在更大的灵活性。
MySQL 的字符集包括字符集(character)和校对规则(collation)两个概念。
- 字符集用来定义存储字符串的方式。
- 校对规则用来定义比较字符串的方式。
- 字符集和校对规则是一对多的关系,MySQL 支持 30 多种字符集的 70 多种校对规则。
校对规则命名约定:它们以其相关的字符集名开始,通常包括一个语言名,并且以
_ci
(大小写不敏感)、_cs
(大小写敏感)或_bin
(二元,即比较是基于字符编码的值而与 language 无关)结束。
1.2 查看字符集常用命令
1)查看所有可用的字符集
# 查看所有可用的字符集 > show character set; +----------+---------------------------------+---------------------+--------+ | Charset | Description | Default collation | Maxlen | +----------+---------------------------------+---------------------+--------+ | armscii8 | ARMSCII-8 Armenian | armscii8_general_ci | 1 | | ascii | US ASCII | ascii_general_ci | 1 | | big5 | Big5 Traditional Chinese | big5_chinese_ci | 2 | | binary | Binary pseudo charset | binary | 1 | | cp1250 | Windows Central European | cp1250_general_ci | 1 | | cp1251 | Windows Cyrillic | cp1251_general_ci | 1 | | cp1256 | Windows Arabic | cp1256_general_ci | 1 | | cp1257 | Windows Baltic | cp1257_general_ci | 1 | | cp850 | DOS West European | cp850_general_ci | 1 | | cp852 | DOS Central European | cp852_general_ci | 1 | | cp866 | DOS Russian | cp866_general_ci | 1 | | cp932 | SJIS for Windows Japanese | cp932_japanese_ci | 2 | | dec8 | DEC West European | dec8_swedish_ci | 1 | | eucjpms | UJIS for Windows Japanese | eucjpms_japanese_ci | 3 | | euckr | EUC-KR Korean | euckr_korean_ci | 2 | | gb18030 | China National Standard GB18030 | gb18030_chinese_ci | 4 | | gb2312 | GB2312 Simplified Chinese | gb2312_chinese_ci | 2 | | gbk | GBK Simplified Chinese | gbk_chinese_ci | 2 | | geostd8 | GEOSTD8 Georgian | geostd8_general_ci | 1 | | greek | ISO 8859-7 Greek | greek_general_ci | 1 | | hebrew | ISO 8859-8 Hebrew | hebrew_general_ci | 1 | | hp8 | HP West European | hp8_english_ci | 1 | | keybcs2 | DOS Kamenicky Czech-Slovak | keybcs2_general_ci | 1 | | koi8r | KOI8-R Relcom Russian | koi8r_general_ci | 1 | | koi8u | KOI8-U Ukrainian | koi8u_general_ci | 1 | | latin1 | cp1252 West European | latin1_swedish_ci | 1 | | latin2 | ISO 8859-2 Central European | latin2_general_ci | 1 | | latin5 | ISO 8859-9 Turkish | latin5_turkish_ci | 1 | | latin7 | ISO 8859-13 Baltic | latin7_general_ci | 1 | | macce | Mac Central European | macce_general_ci | 1 | | macroman | Mac West European | macroman_general_ci | 1 | | sjis | Shift-JIS Japanese | sjis_japanese_ci | 2 | | swe7 | 7bit Swedish | swe7_swedish_ci | 1 | | tis620 | TIS620 Thai | tis620_thai_ci | 1 | | ucs2 | UCS-2 Unicode | ucs2_general_ci | 2 | | ujis | EUC-JP Japanese | ujis_japanese_ci | 3 | | utf16 | UTF-16 Unicode | utf16_general_ci | 4 | | utf16le | UTF-16LE Unicode | utf16le_general_ci | 4 | | utf32 | UTF-32 Unicode | utf32_general_ci | 4 | | utf8 | UTF-8 Unicode | utf8_general_ci | 3 | | utf8mb4 | UTF-8 Unicode | utf8mb4_0900_ai_ci | 4 | +----------+---------------------------------+---------------------+--------+ 41 rows in set (0.00 sec)
2)查看默认安装的字符集
# 查看默认安装的字符集 > show variables like '%char%'; +--------------------------+-----------------------------------------------------------+ | Variable_name | Value | +--------------------------+-----------------------------------------------------------+ | character_set_client | utf8mb4 | | character_set_connection | utf8mb4 | | character_set_database | utf8mb4 | | character_set_filesystem | binary | | character_set_results | utf8mb4 | | character_set_server | utf8mb4 | | character_set_system | utf8 | | character_sets_dir | /usr/local/mysql-8.0.11-macos10.13-x86_64/share/charsets/ | +--------------------------+-----------------------------------------------------------+ 8 rows in set (0.01 sec)
3)显示所有的字符集和该字符集默认的校对规则
# 显示所有的字符集和该字符集默认的校对规则 > desc information_schema.character_sets; +----------------------+------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------------------+------------------+------+-----+---------+-------+ | CHARACTER_SET_NAME | varchar(64) | NO | | NULL | | | DEFAULT_COLLATE_NAME | varchar(64) | NO | | NULL | | | DESCRIPTION | varchar(2048) | NO | | NULL | | | MAXLEN | int(10) unsigned | NO | | NULL | | +----------------------+------------------+------+-----+---------+-------+ 4 rows in set (0.00 sec)
4)查看相关字符集的校对规则
# 查看相关字符集的校对规则 # show collation like 字符集名; > show collation like 'gbk%'; +----------------+---------+----+---------+----------+---------+---------------+ | Collation | Charset | Id | Default | Compiled | Sortlen | Pad_attribute | +----------------+---------+----+---------+----------+---------+---------------+ | gbk_bin | gbk | 87 | | Yes | 1 | PAD SPACE | | gbk_chinese_ci | gbk | 28 | Yes | Yes | 1 | PAD SPACE | +----------------+---------+----+---------+----------+---------+---------------+ 2 rows in set (0.00 sec)
- 上面例子中 GBK 的校对规则,其中
gbk_chinese_ci
是默认的校对规则,对大小写不敏感;而gbk_bin
按照编码的值进行比较,对大小写敏感。
# 查看相关字符集的校对规则 > desc information_schema.collations; +--------------------+---------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------------------+---------------------+------+-----+---------+-------+ | COLLATION_NAME | varchar(64) | NO | | NULL | | | CHARACTER_SET_NAME | varchar(64) | NO | | NULL | | | ID | bigint(20) unsigned | NO | | 0 | | | IS_DEFAULT | varchar(3) | NO | | | | | IS_COMPILED | varchar(3) | NO | | | | | SORTLEN | int(10) unsigned | NO | | NULL | | | PAD_ATTRIBUTE | varchar(9) | NO | | NULL | | +--------------------+---------------------+------+-----+---------+-------+ 7 rows in set (0.00 sec)
- 上面例子中 GBK 的校对规则,其中
2、MySQL 字符集设置
MySQL 的字符集和校对规则有 4 个级别的默认设置:服务器级、数据库级、表级和字段级,它们分别在不同的地方设置,作用也不相同。
查看默认安装的字符集
# 查看默认安装的字符集 > show variables like '%char%'; +--------------------------+-----------------------------------------------------------+ | Variable_name | Value | +--------------------------+-----------------------------------------------------------+ | character_set_client | utf8mb4 | | character_set_connection | utf8mb4 | | character_set_database | utf8mb4 | | character_set_filesystem | binary | | character_set_results | utf8mb4 | | character_set_server | utf8mb4 | | character_set_system | utf8 | | character_sets_dir | /usr/local/mysql-8.0.11-macos10.13-x86_64/share/charsets/ | +--------------------------+-----------------------------------------------------------+ 8 rows in set (0.01 sec)
- 如果
character_set_database
和character_set_server
依然是 latin1 的字符集,也就是说 mysql 后续创建的表都是 latin1 字符集的,不是 utf8,会造成一些麻烦。所以有必要修改 my.cnf,在修改 my.cnf 之前一定要关闭 mysql 进程,不然会遇到 mysql 的 sock 不能连接的问题。
- 如果
2.1 服务器字符集设置
1)查看服务器字符集
可以用以下命令查看当前服务器的字符集和校对规则
# 查看当前服务器的字符集 > show variables like 'character_set_server'; +----------------------+---------+ | Variable_name | Value | +----------------------+---------+ | character_set_server | utf8mb4 | +----------------------+---------+ 1 row in set (0.00 sec) # 查看当前服务器的校对规则 > show variables like 'collation_server'; +------------------+--------------------+ | Variable_name | Value | +------------------+--------------------+ | collation_server | utf8mb4_0900_ai_ci | +------------------+--------------------+ 1 row in set (0.00 sec)
2)设置服务器字符集
服务器字符集和校对规则,可以在 MySQL 服务启动的时候确定。
可以在 my.cnf 中设置
[mysqld] character-set-server=gbk
或者在启动选项中指定
mysqld --character-set-server=gbk
或者在编译时指定
shell> cmake . -DDEFAULT_CHARSET=gbk
如果没有特别的指定服务器字符集,那么默认使用 latin1 作为服务器字符集。上面 3 种设置的方式都只指定了字符集,没有指定校对规则,这样意味着使用该字符集默认的校对规则。如果要使用该字符集的非默认校对规则,则需要在指定字符集的同时指定校对规则。
2.2 数据库字符集设置
数据库的字符集和校对规则在创建数据库的时候指定,也可以在创建完数据库后通过 “alter database” 命令进行修改。需要注意的是,如果数据库里已经存在数据,因为修改字符集并不能将已有的数据按照新的字符集进行存放,所以不能通过修改数据库的字符集直接修改数据的内容。
设置数据库字符集的规则如下
- 如果指定了字符集和校对规则,则使用指定的字符集和校对规则;
- 如果指定了字符集没有指定校对规则,则使用指定字符集的默认校对规则;
- 如果指定了校对规则但未指定字符集,则字符集使用与该校对规则关联的字符集;
- 如果没有指定字符集和校对规则,则使用服务器字符集和校对规则作为数据库的字符集和校对规则。
推荐在创建数据库时明确指定字符集和校对规则,避免受到默认值的影响。
1)查看当前数据库的字符集和校对规则
# 查看当前数据库的字符集 > show variables like 'character_set_database'; +------------------------+---------+ | Variable_name | Value | +------------------------+---------+ | character_set_database | utf8mb4 | +------------------------+---------+ 1 row in set (0.01 sec) # 查看当前数据库的校对规则 > show variables like 'collation_database'; +--------------------+--------------------+ | Variable_name | Value | +--------------------+--------------------+ | collation_database | utf8mb4_0900_ai_ci | +--------------------+--------------------+ 1 row in set (0.01 sec)
2)设置数据库字符集
# 创建数据库时指定数据的字符集 # create database 数据库名 character set 字符集; > create database test character set gbk; Query OK, 1 row affected (0.02 sec)
> use test; Database changed > show variables like 'character_set_database'; +------------------------+-------+ | Variable_name | Value | +------------------------+-------+ | character_set_database | gbk | +------------------------+-------+ 1 row in set (0.01 sec) > show variables like 'collation_database'; +--------------------+----------------+ | Variable_name | Value | +--------------------+----------------+ | collation_database | gbk_chinese_ci | +--------------------+----------------+ 1 row in set (0.00 sec)
3)修改数据库字符集
# 修改数据库字符集 # alter database 数据库名 character set 字符集; > alter database test character set utf8; Query OK, 1 row affected, 1 warning (0.10 sec)
> show variables like 'character_set_database'; +------------------------+-------+ | Variable_name | Value | +------------------------+-------+ | character_set_database | utf8 | +------------------------+-------+ 1 row in set (0.01 sec) > show variables like 'collation_database'; +--------------------+-----------------+ | Variable_name | Value | +--------------------+-----------------+ | collation_database | utf8_general_ci | +--------------------+-----------------+ 1 row in set (0.00 sec)
2.3 表字符集设置
表的字符集和校对规则在创建表的时候指定,可以通过 “alter table” 命令进行修改,同样,如果表中已有记录,修改字符集对原有的记录并没有影响,不会按照新的字符集进行存放。表的字段仍然使用原来的字符集。
设置表的字符集的规则和上面基本类似
- 如果指定了字符集和校对规则,使用指定的字符集和校对规则;
- 如果指定了字符集没有指定校对规则,使用指定字符集的默认校对规则;
- 如果指定了校对规则但未指定字符集,则字符集使用与该校对规则关联的字符集;
- 如果没有指定字符集和校对规则,使用数据库字符集和校对规则作为表的字符集和校对规则。
推荐在创建表的时候明确指定字符集和校对规则,以避免受到默认值的影响。
1)查看当前表的字符集和校对规则
# 查看当前表的字符集和校对规则 # show create table 表名; > show create table test; +-------+--------------------------------------------------------------------------------------------+ | Table | Create Table | +-------+--------------------------------------------------------------------------------------------+ | test | CREATE TABLE `test` ( `c1` float(10,2) DEFAULT NULL, `c2` decimal(10,2) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci | +-------+--------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec)
2)设置表字符集
# 创建表时指定数据的字符集 # create table 表名 ( 列名称字段 数据类型(长度) 约束条件, 列名称字段 数据类型(长度) 约束条件 ) default charset = 字符集名; > create table test ( no int, name varchar(20), age int, score int ) default charset = gbk; Query OK, 0 rows affected (0.08 sec)
3)修改表字符集
# 修改表的字符集 # alter table 表名称 cahracter set 字符集; > alter table test character set utf8; Query OK, 0 rows affected (0.05 sec) Records: 0 Duplicates: 0 Warnings: 0
2.4 列字符集设置
MySQL 可以定义列级别的字符集和校对规则,主要是针对相同的表不同字段需要使用不同的字符集的情况,应该说一般遇到这种情况的几率比较小,这只是 MySQL 提供给我们一个灵活设置的手段。
列字符集和校对规则的定义可以在创建表时指定,或者在修改表时调整,如果在创建表的时候没有特别指定字符集和校对规则,则默认使用表的字符集和校对规则。
2.5 连接字符集设置
上面 4 种设置方式,确定的是数据保存的字符集和校对规则,对于实际的应用访问来说,还存在客户端和服务器之间交互的字符集和校对规则的设置。
对于客户端和服务器的交互操作,MySQL 提供了 3 个不同的参数
character_set_client
:客户端character_set_connection
:连接character_set_results
:返回结果
通常情况下,这 3 个字符集应该是相同的,才可以确保用户写入的数据可以正确地读出,特别是对于中文字符,不同的写入字符集和返回结果字符集将导致写入的记录不能正确读出。
另外,字符串常量的字符集也是由
character_set_connection
参数来指定的。1)设置连接字符集
通常情况下,不会单个地设置这 3 个参数,可以通过以下命令来设置连接的字符集和校对规则,这个命令可以同时修改这 3 个参数的值。使用这个方法修改连接的字符集和校对规则,需要应用每次连接数据库后都执行这个命令。
# set names 字符集; > set names gbk; Query OK, 0 rows affected (0.00 sec) > show variables like '%char%'; +--------------------------+-----------------------------------------------------------+ | Variable_name | Value | +--------------------------+-----------------------------------------------------------+ | character_set_client | gbk | | character_set_connection | gbk | | character_set_database | gbk | | character_set_filesystem | binary | | character_set_results | gbk | | character_set_server | utf8mb4 | | character_set_system | utf8 | | character_sets_dir | /usr/local/mysql-8.0.11-macos10.13-x86_64/share/charsets/ | +--------------------------+-----------------------------------------------------------+ 8 rows in set (0.01 sec)
另一个更简便的办法,是在 my.cnf 中设置以下语句,这样服务器启动后,所有连接默认就是使用 GBK 字符集进行连接的,而不需要在程序中再执行 “set names” 命令。
[mysql] default-character-set=gbk
2)设置字符串字符集
可以通过
[_charset_name]'string' [COLLATE collation_name]
命令强制字符串的字符集和校对规则。> select _gbk '字符集'; > select _latin1 '字符集';
通常情况下,基本不需要用户强制指定字符串字符集。
2.6 字符集的修改步骤
如果在应用开始阶段没有正确地设置字符集,在运行一段时间以后才发现存在不能满足要求需要调整,又不想丢弃这段时间的数据,那么就需要进行字符集的修改。字符集的修改不能直接通过
alter database character set ***
或者alter table tablename character set ***
命令进行,这两个命令都没有更新已有记录的字符集,而只是对新创建的表或者记录生效。已有记录的字符集调整,需要先将数据导出,经过适当的调整重新导入后才可完成。以下模拟的是将 latin1 字符集的数据库修改成 gbk 字符集的数据库的过程。
1)导出表结构
# mysqldump -uroot -p --default-character-set=目标字符集 -d 源数据库名> 目标文件路径.sql $ mysqldump -uroot -p --default-character-set=gbk -d test> /Users/haiqianj/Desktop/testdbcreatetab.sql
- 其中
--default-character-set=gbk
表示设置以什么字符集连接,-d
表示只导出表结构,不导出数据。
- 其中
2)打开 testdbcreatetab.sql,将表结构定义中的字符集修改为新的字符集
-- -- Table structure for table `A` -- DROP TABLE IF EXISTS `A`; /*!40101 SET @saved_cs_client = @@character_set_client */; SET character_set_client = gbk ; CREATE TABLE `A` ( `ano` int(11) NOT NULL, `aname` varchar(20) CHARACTER SET gbk COLLATE gbk_chinese_ci DEFAULT NULL, `loc` varchar(100) CHARACTER SET gbk COLLATE gbk_chinese_ci DEFAULT NULL, PRIMARY KEY (`ano`) ) ENGINE=InnoDB DEFAULT CHARSET=gbk; /*!40101 SET character_set_client = @saved_cs_client */;
3)确保记录不再更新,导出所有记录
# mysqldump -uroot -p --quick --no-create-info --extended-insert --default-character-set=源字符集 源数据库名> 目标文路径.sql $ mysqldump -uroot -p --quick --no-create-info --extended-insert --default-character-set=latin1 test> /Users/haiqianj/Desktop/testdbdata.sql
--quick
:该选项用于转储大的表。它强制 mysqldump 从服务器一次一行地检索表中的行而不是检索所有行,并在输出前将它缓存到内存中。--extended-insert
:使用包括几个 values 列表的多行 insert 语法。这样使转储文件更小,重载文件时可以加速插入。--no-create-info
:不导出每个转储表的 create table 语句。--default-character-set=latin1
:按照原有的字符集导出所有数据,这样导出的文件中,所有中文都是可见的,不会保存成乱码。
4)打开 testdbdata.sql,将
set names latin1
修改成set names gbk
set names 目标字符集; set names gbk;
5)使用新的字符集创建新的数据库
# create database 新数据库名 default charset 目标字符集; > create database newtest default charset gbk;
6)创建表,执行 testdbcreatetab.sql
# mysql -uroot -p 新数据库名 < 目标文路径.sql $ mysql -uroot -p newtest < /Users/haiqianj/Desktop/testdbcreatetab.sql
7)导入数据,执行 testdbdata.sql
# mysql -uroot -p 新数据库名 < 目标文路径.sql $ mysql -uroot -p newtest < /Users/haiqianj/Desktop/testdbdata.sql
8)查看修改后的数据库
> show create database newtest; +----------+-----------------------------------------------------------------+ | Database | Create Database | +----------+-----------------------------------------------------------------+ | newtest | CREATE DATABASE `newtest` /*!40100 DEFAULT CHARACTER SET gbk */ | +----------+-----------------------------------------------------------------+ 1 row in set (0.00 sec) > show create table A; +-------+-------------------------------------------------------------------------------------------------------+ | Table | Create Table | +-------+-------------------------------------------------------------------------------------------------------+ | A | CREATE TABLE `A` ( `ano` int(11) NOT NULL, `aname` varchar(20) CHARACTER SET gbk COLLATE gbk_chinese_ci DEFAULT NULL, `loc` varchar(100) CHARACTER SET gbk COLLATE gbk_chinese_ci DEFAULT NULL, PRIMARY KEY (`ano`) ) ENGINE=InnoDB DEFAULT CHARSET=gbk | +-------+-------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec)
注意:选择目标字符集的时候,要注意最好是源字符集的超集,或者确定比源字符集的字库更大,否则如果目标字符集的字库小于源字符集的字库,那么目标字符集中不支持的字符导入后会变成乱码,丢失一部分数据。例如,GBK 字符集的字库大于 GB 2312 字符集,那么 GBK 字符集的数据,如果导入 GB 2312 数据库中,就会丢失 GB 2312 中不支持的那部分汉字的数据。