目录
一、字符集概念
1、字符(Character)
2、字符编码
3、字符集(Character set)
二、字符集原理
1、ASCII字符集
2、GB2312
3、GBK
4、GB18030
5、BIG5
6、Unicode 编码
三、字符序
四、MySQL字符集 & 字符序
1、mysql 字符集
2、mysql 字符序
3、字符集与字符序的关系
五、MySQL 数据存储字符集
1. 字符集层级关系
2、如何设置字符集
2.1 服务器字符集设置
2.2 数据库字符集设置
2.3 数据表字符集设置
2.4 字段字符集设置
3、多级的字符集 & 多种字符集的作用
六、MySQL 客户端与服务端交互字符集
1、交互示意图
2、如何设置字符集
我们在使用 MySQL 的过程中,经常会碰到诸如乱码之类的问题。字符编码与字符集密切相关,MySQL 支持种类繁多的字符集类型,这些字符集到底如何影响 MySQL 数据存储与数据传输的呢?我们该如何选择正确的字符集?那就通过这篇文章来帮你捋清细节和解除困扰吧!
本文依赖以下环境:
操作系统:MAC OS 10.11.6
MySQL:Server version: 5.6.21 MySQL Community Server (GPL)
字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字、(emoji表情)等属于字符的范畴。
计算机是通过 BIT 来存储数据的,将人类可识别的字符转换成计算机能够存储的形式,这个过程就是字符编码。
字符集是多个字符的集合,包含一组字符以及对应的编码方式。字符集种类较多,每个字符集包含的字符个数和编码方式不同,常见字符集名称:ASCII 字符集、GB2312 字符集、BIG5 字符集、 GB18030 字符集、Unicode 字符集等。
我们熟知的 ASCII 字符集是一种现代美国英语适用的字符集。包括的字符有数字、大小写字母、分号、换行之类的符号,编码方式是用一个 7bit 表示一个字符,例如A的编码是 65,b 的编码是 98。
ASCII(American Standard Code for Information Interchange,美国标准信息交换代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言,主要编码表如下图所示。
GB2312 字符集是一种对汉字比较友好的字符集,共收录 6700 多个汉字,基本涵盖了绝大部分常用汉字。不过,GB2312 字符集不支持绝大部分的生僻字和繁体字。对于英语字符,GB2312 编码和 ASCII 码是相同的,1 字节编码即可。对于非英字符,需要 2 字节编码。
GBK 字符集可以看作是 GB2312 字符集的扩展,兼容 GB2312 字符集,共收录了 20000 多个汉字。GBK 中 K 是汉语拼音 Kuo Zhan(扩展)中的 “Kuo” 的首字母。
GB18030 完全兼容 GB2312 和 GBK 字符集,纳入中国国内少数民族的文字,且收录了日韩汉字,是目前为止最全面的汉字字符集,共收录汉字 70000 多个。
BIG5 主要针对的是繁体中文,收录了 13000 多个汉字。
ASCII 只对英文符号和英文字母做了编码,GB2312对英文符号,英文字母,汉字做了编码。每个国家为了更加适合本国语言,都有一套自己的字符集。不同的字符集可以表示的字符范围以及编码规则存在差异。同一个编码,对于不同的字符集来说就可能代表不同的字符:
这就导致了一个非常严重的问题:使用错误的编码方式查看一个包含字符的文件就会产生乱码现象。就比如说你使用 UTF-8 编码方式打开 GB2312 编码格式的文件就会出现乱码。示例:“牛”这个汉字 GB2312 编码后的十六进制数值为 “C5A3”,而 “C5A3” 用 UTF-8 解码之后得到的却是 “ţ”。
为了解决不同语言编码之间不兼容的问题,Unicode 出现了。Unicode 字符集致力于为全世界每一个语言的每一个字符都有统一且唯一的编码,Unicode 字符序号的范围是 0x000000 到0x10FFFF,可以容纳 110 多万个字符。UTF8、UTF16、UTF32 是 Unicode 编码的不同实现方式:
一个字符集中有多个字符,那么如何对其中的字符进行排序呢?这就是字符序。简单来说,字符序就是字符排序的规则集合。
一个字符集中有多个字符,那么如何对其中的字符进行排序呢?这就是字符序。比如一个字符集有下面几个字符以及字符编码:
我们可以直接按照 A > B > a > b 的规则来进行排序,这就是这个简单字符集的一个字符序。如果想让小写字母放在前面,比如 a > b > A > B,这又是一种字符序。如果还想加上大小写无关或大小写相关,这就产生了不同的字符序。
接下来我们来看看 MySQL 的字符集与字符序。MySQL 目前支持多种字符集,支持在不同的字符集之间转换(便于移植和支持多语言)。
通过命令: mysql -u[username] -p[password] 连接上MySQL后,用下面命令查询MySQL 支持的字符集:
SHOW CHARACTER SET;
结果:
指定条件查询:
SHOW CHARACTER SET LIKE 'utf%';
结果:
字段含义:
每个字符集都对应一个或多个字符序,可以通过下面的语句查看所有的字符序:
SHOW COLLATION;
结果(部分展示):
指定条件查询:
SHOW COLLATION WHERE Charset = 'utf8mb4';
结果:
字段含义:
每个字符序都是以该字符序所关联的字符集为前缀的,同时还有一些有规律的后缀:
同时有的字符序是面向某种语言的,也会在字符序名字中有所体现,比如big5_chinese_ci。
字符集与字符序的关系可以上面的图来表示:
MySQL 是按层级来设定字符集与字符序的,MySQL 可以设置:服务器级字符集、数据库级字符集、数据表级字符集、表列级别字符集。实际上,最终使用字符集的地方是存储字符的列,它决定了数据库中存储的数据采用哪个字符集的编码和字符序。
结构图:
层级图:
如上图所示:
上一层级如果没有指定字符集与字符序,就采用下一层级的字符集与字符序。也就是说:新建数据库时没有指定字符集,就默认设置为服务器的字符集;如果新建数据表时没有指定字符集,就默认设置为数据库的字符集;如果向数据表添加新列时没有指定列的字符集,那么这些列就默认设置为数据表的字符集。与字符集相同,如果不特别指定,字符序也采取了默认值继承的方式。
另一方面,直接改变这四个层次的编码并不会改变它们各自所有下层对象的当前编码。比如修改 Server 级,那么所有已经存在的数据库、数据表、表、列的字符集都不会发生改变。同时,数据表中每一条现有记录的字符字段仍然是按原来的编码存储的。
我们先来看下,MySQL 刚安装完,MySQL 字符集的的初始字符集和字符序是什么?
查看字符集变量:
SHOW VARIABLES LIKE 'character_set\_%';
查看字符序变量:
SHOW VARIABLES LIKE '%collation%';
查询结果:
character_set_server:服务器的字符集是 latin1
collation_server: 服务器的字符序是 latin1_swedish_ci
character_set_database:数据库的字符集是 latin1
collation_database:数据库的字符序是 latin1_swedish_ci
从上图可以看出,MySQL 服务器安装后已经初始化了服务器和数据库的默认字符集和字符序,另外,我们在创建数据库、表、添加字段时,都可以默认采用上一级的字符集和字符序,也可以在创建时自行指定:
通过 character_set_server 变量的设定字符集的几个方式:
方式1:在 my.cnf 中配置
[mysqld]
character-set-server=utf8
方式2:启动时配置参数
mysqld --charater-set-server=utf8
方式3:编译时指定
[root@database-one ~]# cmake . -DDEFAULT_CHARSET=utf8
// -- 示例: 创建数据库
create database if not exists dbtest character set utf8;
// -- 示例:修改数据库
ALTER DATABASE dbtest CHARACTER SET 'utf8';
// -- 创建表时:DEFAULT CHARSET=utf8mb4 设置字符集
CREATE TABLE `t_employee` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '员工ID',
`code` varchar(10) NOT NULL COMMENT '员工编码',
`name` varchar(10) NOT NULL COMMENT '员工姓名',
`age` int(10) unsigned DEFAULT NULL COMMENT '年龄',
`sex` int(10) unsigned DEFAULT NULL COMMENT '性别',
`cert_type` int(10) unsigned DEFAULT NULL COMMENT '证件类型',
`cert_no` varchar(20) DEFAULT NULL COMMENT '证件号',
`birthday` date DEFAULT NULL COMMENT '生日',
`income_date` date DEFAULT NULL COMMENT '入职日期',
PRIMARY KEY (`id`),
UNIQUE KEY `code` (`code`),
UNIQUE KEY `cert_type` (`cert_type`,`cert_no`)
) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8mb4 COMMENT='员工表';
// -- 修改表的字符集
ALTER TABLE `dbtest`.`t_employee` CHARACTER SET = utf8mb4;
// -- 创建表时:CHARACTER SET utf8mb4指定字段字符集
CREATE TABLE `t_employee` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '员工ID',
`code` varchar(10) NOT NULL COMMENT '员工编码',
`name` varchar(10) NOT NULL COMMENT '员工姓名',
`age` int(10) unsigned DEFAULT NULL COMMENT '年龄',
`sex` int(10) unsigned DEFAULT NULL COMMENT '性别',
`cert_type` int(10) unsigned DEFAULT NULL COMMENT '证件类型',
`cert_no` varchar(20) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '证件号',
`birthday` date DEFAULT NULL COMMENT '生日',
`income_date` date DEFAULT NULL COMMENT '入职日期',
PRIMARY KEY (`id`),
UNIQUE KEY `code` (`code`),
UNIQUE KEY `cert_type` (`cert_type`,`cert_no`)
) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8 COMMENT='员工表';
// -- 修改字段的字符集:CHARACTER SET utf8mb4
ALTER TABLE `dbtest`.`t_employee`
MODIFY COLUMN `cert_no` varchar(20) CHARACTER SET utf8mb4 NULL DEFAULT NULL COMMENT '证件号' AFTER `cert_type`;
多级继承的字符集与字符序:可以方便快捷的确定下一层级的字符集和字符序,比如一个数据库下面有很多张表,只需要将数据库的字符集设置为 UTF8,所有表创建时就指定了默认的字符集。
早期只支持有限数量字符集,后来不断的扩展,例如早期的 UTF8(阉割版本,早期 MySQL 版本为了节省存储空间,最多三个字节)完全够用了,后面出现了 EMOJI 表情符号、比较复杂的汉字、繁体字又不能满足要求了,于是有 utf8mb4 字符集。并且支持在同一个服务器下数据库有不同的字符集,同一个数据库下的不同表也可以设定不同的字符集,同一个表的不同字段也可以设定不同的字符集,都是为了方便业务的移植和扩展。(例如以前一个业务只覆盖了欧洲英文国家,采用 ladin 1字符集就足够了,但是后来有扩展到中国,于是需要将字符集扩展到 UTF8;之前全部采用UTF8字符集,但是发现用户注册的昵称使用了 EMOJI 表情符号,于是将 nickname 字段的字符集修改为 utf8mb4)。
上面 4 种级别的字符集都是用于数据保存的,其实客户端和服务器之间的交互也受到字符集和校对规则的影响。
MySQL提供了character_set_client、character_set_connection 和 character_set_results 三个参变量:
character_set_client
character_set_connection
character_set_results
既:
character_set_client
;character_set_connection
字符集;character_set_results
字符集。方式1:在 MySQL 配置文件中设置 my.cnf:
[client]
default-character-set=utf8
方式2:在客户端执行:
SET NAMES utf8;
方式3:在连接地址配置:
jdbc:mysql://localhost:3306/mydatabase?useUnicode=true&characterEncoding=utf8
以上三种方式等效于在客户端同时执行三条命令:
SET character_set_client utf8;
SET character_set_connection utf8;
SET character_set_results utf8;
参考:
MySQL配置文件my.ini详解
你真的搞懂MySQL的字符集了吗?
MySQL字符集的不同级别和效果
深入理解MySQL字符集及校对规则(一)
MySQL的字符编码体系(一)——数据存储编码
MySQL-解析客户端SQL执行字符集参数设置
MySQL中的字符集与字符序