一、概念
字符集与排序规则相辅相成,相互依赖关联,部分数据库没有做明确区分(如sql sever)。
字符(charcter):是文字和符号的总称,包括文字、图形符号、数字符号等。例如英文字母和汉字
字符集是一组抽象的字符组成的集合,不是一个简单的字符的集合,而是一套符号和编码规则。需要以某种字符编码方式来表示、存储字符。例如用不同的0、1组合来表示不同字符就是编码
准确概述来说,字符编码方式是用一个或多个字节的二进制形式表示字符集中的一个字符。每种字符集都有自己特有的编码方式,因此同一个字符,在不同字符集的编码方式下,可能会产生不同的二进制形式。
另外,字符集合只是指定了一个集合中有哪些字符,而字符编码,是为这个集合中所有字符定义相关编号,而字符集(注意与字符集合的区别)是字符和集合与编码规则的混合体。
Unicode(统一码、万国码、单一码)是一种字符集,Unicode是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。Unicode用数字0-0x10FFFF来映射这些字符,最多可以容纳1114112个字符,或者说有1114112个码位。UTF-8、UTF-16、UTF-32都是将数字转换到程序数据的编码方案。.在Unicode中:汉字“中”对应的数字是20013。我们可以用:UTF-8、UTF-16、UTF-32表示这个数字,将数字20013存储在计算机中。UTF-8对应是:E4B8AD,UTF-16对应是:FEFF4E2D,UTF-32对应是:0000FEFF00004E2D。简单来说,UTF-8、UTF-16、UTF-32是Unicode码一种实现形式,都是属于Unicode编码。
二、mysql字符集
mysql中常见字符集有GBK,GB2312,UTF8,UTF8mb4,UTF16等;
mysql中的排序规则一般指对字符集中字符串的比较、排序制定的规则;
mysql的排序规则特征:
·两个不同的字符集不能有相同的校对规则;
·每个字符集有一个默认校对规则;
·存在校对规则命名约定:以其相关的字符集名开始,中间包括一个语言名,并且以_ci(大小写不敏感)、_cs(大小写敏感)或_bin(二元)结束
其实对于排序规则的细节问题,我们关注较少,反而对排序规则中是否涉及大小写敏感关注较多。 例如,系统使用utf8字符集,若使用utf8_bin校对规则执行SQL查询时区分大小写,使用utf8_general_ci不区分大小写(默认的utf8字符集对应的校对规则是utf8_general_ci)。
三、mysql系统变量相关字符集
mysql> show variables like 'character_set%'; // 查看当前系统变量字符集设置
| Variable_name | Value | 备注 |
|---|---|---|
| character_set_client | utf8 | 客户端数据使用的字符集。MySQL Client发送给mysqld的语句或数据使用字符集 |
| character_set_connection | utf8 | 连接层字符集。用于没有introducer修饰的字符串和数字到字符串的转换。 由introducer修饰的文本字符串在请求过程中不经过多余的转码,直接转换为内部字符集处理。 |
| character_set_database | utf8mb4 | 数据库字符集。 |
| character_set_filesystem | binary | 文件系统字符集。用于解释引用文件名的字符串文字 |
| character_set_results | utf8 | 查询结果字符集。mysqld在返回查询结果集或者错误信息到客户端时使用的编码字符集 |
| character_set_server | latin1 | 服务器字符集。默认的字符集,数据库不指定字符集讲自动使用此字符集 |
| character_set_system | utf8 | 系统元数据字符集。是系统元数据(表名、字段名等)存储时使用的编码字符集,该字段和具体存储的数据无关。总是固定不变的UTF8字符集。 |
| character_sets_dir | /usr/share/mysql/charsets/ |
mysql> show charset; // 查看mysql支持的字符集// 或mysql> select * from information_schema.character_sets;
四、mysql字符集选择
一般而言,我们可能选择utf8mb4这个字符集,而不选择utf8. 这个是因为MySQL的utf8并不是真正的UTF8字符集,MySQL的utf8字符编码只有三个字节,节省空间但不能表达全部的UTF-8,只能支持“基本多文种平面”(Basic Multilingual Plane,BMP),而utf8mb4才是真正的支持UTF8编码,网上有篇文章专门介绍这个。 一般而言,我们会选择utf8mb4,而不会选择gb2312、gbk。 对于gb2312而言,有些偏僻字(例如:洺)不能保存。gbk是中文字符编码是双字节的。虽然节省空间,但是有可能带来一些其他问题。在当前环境下,相信存储空间对于绝大部分公司来说都不是什么问题。
五、乱码的原因
1.对于数据输入而言
- 在客户端对相关数据进行编码。
2. MySQL接收到请求时,它会询问客户端通过什么方式对字符编码:客户端通过character_set_client系统变量告知MySQL客户端的编码方式,当MySQL发现客户端的client所传输的字符集与自己的connection不一样时,它会将请求数据从character_set_client转换为character_set_connection;
3. 进行内部操作前会将请求数据从character_set_connection转换为内部操作字符集:在存储的时候会判断编码是否与内部存储字符集(按照优先级判断字符集类型,如下所示)上的编码一致,如果不一致需要转换,其流程如下:
• 使用每个数据字段的CHARACTER SET设定值;
• 若上述值不存在,则使用对应数据表的DEFAULT CHARACTER SET设定值(MySQL扩展,非SQL标准);
• 若上述值不存在,则使用对应数据库的DEFAULT CHARACTER SET设定值;
• 若上述值不存在,则使用character_set_server设定值。2.对于数据输出而言
客户端使用的字符集必须通过character_set_results来体现,服务器询问客户端字符集,通过character_set_results将结果转换为与客户端相同的字符集传递给客户端。(character_set_results默认等于character_set_client)
