mysql对字符集的支持有哪些种类,与php有什么区别,mysql各版本间有什么区别?

 

Mysql字符集设置概览

字符集和校对规则有4个级别的默认设置:服务器级、数据库级、表级和连接级。针对每一列,甚至每一个字符串(select _latin1 ‘string’),mysql也可以指定其编码,但是一般不用。其中,服务器、数据库、表、列级都是相对静态的,而连接级相对动态。

数据库支持的编码:

mysql> SHOW CHARACTER SET;
+———-+—————————–+———————+——–+
| Charset | Description | Default collation | Maxlen |
+———-+—————————–+———————+——–+
| dec8 | DEC West European | dec8_swedish_ci | 1 |
| cp850 | DOS West European | cp850_general_ci | 1 |
| hp8 | HP West European | hp8_english_ci | 1 |

……
+———-+—————————–+———————+——–+
28 rows in set (0.00 sec)

针对同一种编码,可以有多种比较规则:

mysql> SHOW COLLATION where Charset = ‘utf8′;
+——————–+———+—–+———+———-+———+
| Collation | Charset | Id | Default | Compiled | Sortlen |
+——————–+———+—–+———+———-+———+
| utf8_general_ci | utf8 | 33 | Yes | Yes | 1 |
……
+——————–+———+—–+———+———-+———+
21 rows in set (0.00 sec)

与编码和比较相关的配置项:

mysql> show variables like ‘%character%';
+————————–+—————————————————+
| Variable_name | Value |
+————————–+—————————————————+
| character_set_client | utf8 |     ; 客户端发送的查询中使用的字符集
| character_set_connection | utf8 | ; 将客户端发送的查询从character_set_client系统变量转换到character_set_connection(除非字符串文字具有象_latin1或_utf8的引介词)

| character_set_database | gbk | ; 默认数据库的字符集
| character_set_filesystem | binary |
| character_set_results | utf8 | ; 服务器返回查询结果到客户端使用的字符集。包括结果数据,例如列值和结果元数据(如列名)。
| character_set_server | gbk | ; 当前的服务器字符集
| character_set_system | utf8 |
| character_sets_dir | /home/mysql/local/mysql6603/share/mysql/charsets/ |
+————————–+—————————————————+
8 rows in set (0.00 sec)

mysql> show variables like ‘%collation%';
+———————-+—————–+
| Variable_name | Value |
+———————-+—————–+
| collation_connection | utf8_general_ci |
| collation_database | gbk_chinese_ci |
| collation_server | gbk_chinese_ci |
+———————-+—————–+
3 rows in set (0.00 sec)

连接级编码,引mysql5.1参考手册如下,并略作调整:

一些字符集和校对规则系统变量与客户端和服务器的交互有关。

在客户端和服务器的连接处理中也涉及了字符集和校对规则变量。每一个客户端有一个连接相关的字符集和校对规则变量。

考虑什么是一个“连接”:它是连接服务器时所作的事情。客户端发送SQL语句,例如查询,通过连接发送到服务器。服务器通过连接发送响应给客户端,例如结果集。对于客户端连接,这样会导致一些关于连接的字符集和 校对规则的问题,这些问题均能够通过系统变量来解决:

·         当查询离开客户端后,在查询中使用哪种字符集?

服务器使用character_set_client变量作为客户端发送的查询中使用的字符集。

·         服务器接收到查询后应该转换为哪种字符集?

转换时,服务器使用character_set_connection和collation_connection系统变量。它将客户端发送的查询从character_set_client系统变量转换到character_set_connection(除非字符串文字具有象_latin1或_utf8的引介词)。collation_connection对比较文字字符串是重要的。对于列值的字符串比较,它不重要,因为列具有更高的 校对规则优先级。

·         服务器发送结果集或返回错误信息到客户端之前应该转换为哪种字符集?

character_set_results变量指示服务器返回查询结果到客户端使用的字符集。包括结果数据,例如列值和结果元数据(如列名)。

根据上文可知,与连接相关的config是character_set_client、character_set_connection、character_set_results。一般,php代码里会通过mysql_set_charset之类的函数,设置希望的连接编码。

混杂字符集的弊端

在文章一开头,提到过,虽然mysql能够对列、字符串设置编码,但是一般不用。理由很简单,这样会造成不必要的困扰。比如在做字符串比较时,不同编码会很复杂。各种字符串操作的函数如果同时涉及不同编码,也会很复杂。而这些,个人认为,不应该加诸于mysql之上,而应该会从架构层面消除。

Mysql UTF8以及陷阱

在记忆中,utf8是变长1-4字节,但是mysql里却明确规定最大为3字节。查询其手册页可见,即mysql的实现中,不支持四字节,这是与php有区别的地方。

UTF8字符集(转换Unicode表示)是存储Unicode数据的一种可选方法。它根据 RFC 3629执行。UTF8字符集的思想是不同Unicode字符采用变长字节序列编码:

·         基本拉丁字母、数字和标点符号使用一个字节。

·         大多数的欧洲和中东手写字母适合两个字节序列:扩展的拉丁字母(包括发音符号、长音符号、重音符号、低音符号和其它音符)、西里尔字母、希腊语、亚美尼亚语、希伯来语、阿拉伯语、叙利亚语和其它语言。

·         韩语、中文和日本象形文字使用三个字节序列。

RFC 3629说明了采用一到四个字节的编码序列。当前,MySQLUTF8不支持四个字节。(UTF8编码的旧标准是由RFC 2279给出,它描述了从一到六个字节的UTF8编码序列。RFC 3629补充了作废的RFC 2279;因此,不再使用5个字节和6个字节的编码序列。)

提示:使用UTF8时为了节省空间,使用VARCHAR而不要用CHAR。否则,MySQL必须为一个CHAR(10) CHARACTER SET utf8列预备30个字节,因为这是可能的最大长度。

这里需要注意的是,length和char_length的结果会有区别(utf8和gbk等都有该问题),比如,针对一张gbk编码的表:

mysql> select username, length(username), char_length(username) from user where userid = 1 or userid = 2;
+————+——————+———————–+
| username | length(username) | char_length(username) |
+————+——————+———————–+
| engname | 7 | 7 |
| 我真是汉字 | 10 | 5 |
+————+——————+———————–+

可见,length返回的是它真实占用的存储字节数,而char_length是字符数。在php中同样有这些问题,strlen的结果和mb_strlen的结果就是不相同的。

还有一个需要注意的点,在作为索引列时,会使用length的长度。并且如果一个索引使用了utf8编码的列,那么mysql会假设所有的字符都是3字节的,即使它其实是1-3字节!所以,索引的长度限制会变成平常的1/3!

 

参考URL:

http://dev.mysql.com/doc/refman/5.1/zh/charset.html

http://php.net/manual/zh/mysqlinfo.concepts.charset.php

http://php.net/manual/zh/function.mysql-set-charset.php

Leave a Reply