码迷,mamicode.com
首页 > 数据库 > 详细

【MySQL管理维护-第5章】MySQL字符集三

时间:2015-05-04 20:31:22      阅读:166      评论:0      收藏:0      [点我收藏+]

标签:mysql   字符集   

五、字符集操作示例

   通过一个最简单的示例:“向某测试表插入记录,确保写入的记录能被正确地保存,并能被正常地读取”。

    先来创建一个测试表13,拥有3个列,并为每个列分别指定不同的字符集,所指定的3种字符集,也是目前MySQL环境最为常见的字符集,执行操作如下: 

(system@localhost)[leedb]> use leedb;
Database changed
(system@localhost)[leedb]> 
(system@localhost)[leedb]> 
(system@localhost)[leedb]> create table t3(
    -> v1 varchar(20) charset latin1,
    -> v2 varchar(20) charset gbk,
    -> v3 varchar(20) charset utf8
    -> );
Query OK, 0 rows affected (0.05 sec)

设置当前客户端连接会话的字符集为utf8:

(system@localhost)[leedb]> set names utf8;
Query OK, 0 rows affected (0.00 sec)

(system@localhost)[leedb]> show variables like character%‘;
+--------------------------+----------------------------------+
| Variable_name            | Value                            |
+--------------------------+----------------------------------+
| character_set_client     | utf8                             |
| character_set_connection | utf8                             |
| character_set_database   | utf8                             |
| character_set_filesystem | binary                           |
| character_set_results    | utf8                             |
| character_set_server     | utf8                             |
| character_set_system     | utf8                             |
| character_sets_dir       | /usr/local/mysql/share/charsets/ |
+--------------------------+----------------------------------+
8 rows in set (0.01 sec)


向这个表中插入一条记录,每个列都指定相同的值,中英文字符混合:

(system@localhost)[leedb]> insert into t3 values (‘cn 中国‘,‘cn 中国‘,‘cn 中国‘); 
ERROR 1366 (HY000): Incorrect string value: \xD6\xD0\xB9\xFA for column v1 at row 1

    返回1366号错误信息,细看提示就能明白,原来在提示vl列指定了错误的字符串值,导致插入失败。这个错误提示可以理解,因为前面说过,latinl是西文字符集,并不支持中文这样的多字节字符,因此插入时就报错了。

    不过,考虑到MySQL 5.6正式版本刚出不久,大部分用户仍在使用5.6之前的版本, 需要提醒大家的是,在MySQL 5.6之前版本,1366号信息并非错误,而是一条警告,也就是说在之前版本中,出现这种情况只会抛出一条警告,但插入操作仍能成功。但是,都出现警告 了,实际插入的数据出现异常的概率也就相当的高了,若是以为插入成功,但查询时才发现信息错误,那就麻烦了。因此这就需要大家更加慎重地对待,因为有时候 操作失败报错,要比操作(同样)失败报警更合理一些呐。进入5.6版本后,MySQL修改1366号的错误级别。


提示:此处1366错误级别由系统变量sql_mode来控制

   sql_mode系统变量,顾名思义用来控制SQL模式,MySQL提供的模式众多,不同模式提供了不同的功能或限制条件。在MySQL 5.6版本之前,sql_mode默认为空,而进入到5.6版本后, Sql_mode、默认值改为STRICT_TRANS_TABLES,这个变量值的功能是对于支持事务的存储引擎对象,启动严格限制模式,这种情况下,就会出现插入值非法则直接报错,而非警告。 

若仍然希望像5.6版本之前,插入字符串值不匹配抛出警告而非错误,则将sql_mode值改为空,如果该系统变量拥有多个值,则去除STRICT_TRANS_TABLES值即可。 


下面修改一下col1待插入的值,而后再次执行INSERT语句: 

(system@localhost)[leedb]> insert into t3 values (‘china‘,‘cn 中国‘,‘cn 中国‘); 
ERROR 1366 (HY000): Incorrect string value: \xD6\xD0\xB9\xFA for column v2 at row 1

    又报了几乎一模一样的错误,不过这回变成v2列字符串,即使我们继续尝试,把v2列值改一下,再次尝试插入时又会抛出错误,提示v3列的字符有误。

    vl这种latinl编码的列,插入中文字符出现错误还可以理解,因为它确实不支持中文编码,但为什么v2和v3这两列也会是乱码呢?这两个一个使用gbk编码,一个基于utf8编码,应该是都能够支持中文字符的呀! 

    既然存储阶段的字符集设置没有问题,我们输入的字符也没有问题,那就只有一个可能:连接阶段的字符集编码不对。可是,回想一下,在操作之前,我们己经显式地指定了当前连接会话的字符集为utf8了呀,utf8能够支持中文的不是嘛? 

    utf8编码能够支持中文不假,但是,utf8编码格式下的“中国”,就是我们输入的“中国”这两个字符呢?这明明是gb2312或者说gbk编码的字符形式。 

插入时报错,不是我们输入的不对,或者表列的字符集设置不对,而是客户端的字符集和存储所用字符集不匹配的结果。通过实际操作验证一下,先把当前客户端会话的字符集改为gbk,然后再执行相同的INSERT操作看一看: 

(system@localhost)[leedb]> set names gbk;
Query OK, 0 rows affected (0.00 sec)

(system@localhost)[leedb]> insert into t3 values (‘china‘,‘cn 中国‘,‘cn 中国‘); 
Query OK, 1 row affected (0.01 sec)

(system@localhost)[leedb]> select * from t3;
+-------+---------+---------+
| v1    | v2      | v3      |
+-------+---------+---------+
| china | cn 中国 | cn 中国 |
+-------+---------+---------+
1 row in set (0.00 sec)


可以看到,连接时字符集和存储时的字符集一致,结果才能正常显示。

那么utf8字符集的v3列为什么也能正常显示?就是character_result系统变量的功劳了嘛,它被转换成了 gbk字符集形式.

    再把连接会话的字符集改为utf8,看看表中的记录又会变成什么样呢

(system@localhost)[leedb]> set names utf8;
Query OK, 0 rows affected (0.00 sec)

(system@localhost)[leedb]> select v1,v2,v3,length(v1),length(v2),length(v3) from t3;
+-------+-----------+-----------+------------+------------+------------+
| v1    | v2        | v3        | length(v1) | length(v2) | length(v3) |
+-------+-----------+-----------+------------+------------+------------+
| china | cn 涓浗 | cn 涓浗 |          5 |          7 |          9 |
+-------+-----------+-----------+------------+------------+------------+
1 row in set (0.00 sec)


验证:

(system@localhost)[leedb]> insert into t3 values(‘china‘,‘cn 涓浗‘,‘cn 涓浗‘);
Query OK, 1 row affected (0.04 sec)

(system@localhost)[leedb]> set names gbk;
Query OK, 0 rows affected (0.00 sec)

(system@localhost)[leedb]> select * from t3;
+-------+---------+---------+
| v1    | v2      | v3      |
+-------+---------+---------+
| china | cn 中国 | cn 中国 |
| china | cn 中国 | cn 中国 |
+-------+---------+---------+
2 rows in set (0.00 sec)


可以看到,UTF8编码中的“cn 涓浗”正是GBK编码的“中国”。

 

六、字符集设置

1、字符串的字符集

    字符集是针对MySQL数据库中的字符类型,我们一般设置字符集,都是对存储对象进行设置,这里还有一个很细节的问题,对于那些并非保存在数据库对象里的字符是否拥有字符集呢?比如下面这个语句: 

select ‘cn 中国‘;

    这个语句中的字符串有字符集吗?这点毋庸置疑,字符类型都有字符集。不过出现在SQL语句中某个角落的字符串,多数情况下我们都是理所当然地就用了,它们的字符集却被我们忽视。 

    针对字符串,用户可以在使用时, 通过相应语句来显式地设置字符集及校对规则,其基础语法如下: 

[_charset_name]‘string‘ [COLLATE collation_name]

这其中:

[_charset_name]:指定字符集,其中_符号是固定格式,后面跟字符集名称,由于是可选项,因此一般都忽略了。

‘string‘:列或列值。

[collation_name]:指定校对规则。

下面SQL语句中选择的几个字符串的列值结果是相同的: 

(system@localhost)[leedb]> select cn 中国‘,_gbkcn 中国‘,_utf8cn 涓浗 collate utf8_general_ci;
+---------+---------+-----------------------------------------+
| cn 中国 | cn 中国 | _utf8cn 涓?浗 collate utf8_general_ci |
+---------+---------+-----------------------------------------+
| cn 中国 | cn 中国 | cn 中国                                 |
+---------+---------+-----------------------------------------+
1 row in set (0.00 sec)

    这就是_charset_name表达式的作用,它会告诉解析器使用其后的字符串作为字符集。大多数情况下,我们都忽略了指定字符串的字符集,不管指定不指定,字符串都是有字符集的,那么MySQL是采用何种策略确定该字符串的字符集呢?这其中有一定的规则, 取决于当前的系统环境设置:

  • 如果同时指定了字符集和校对规则,则按照指定的设置。

  • 如果仅指定了校对规则,那么采用校对规则所属的字符集作为默认字符集。 

  • 如果均未指定(通常都是这样),那么会按照系统变量character_set_connection和 collation_connection的设置作为默认的字符集和校对规则。


2、错误提示的字符集

    服务端返回的错误或警告信息也是字符,当然也有字符集.对于MySQL服务来说,服务端固定使用utl8字符集组织错误信息,返回到客户端时,转换成character_set_results系统变量指定的字符集。 

服务端在组织错误或警告信息时,按照下列的方式处理信息的几个组成部分:

  • 首先,消息模板使用utf8字符集。

  • 而后,消息模板中的参数替换成指定的错误事件,包括几个子项: 

> 标识符,比如表名或者列名这类内部即使用utf8字符集的仍然用该字符集输出。 

> 字符串值(不含二进制)则从原始字符集转换成utf8。 

> 二进制字符串转换成字节方式表示,范围在0x20Ox7e之间,超出该范围则使用\x十六进制编码。比如说一个键复制错误,尝试插入0x41CF9F到 VARBINARY唯一列时,返回的错误信息如下: 

Duplicate entry ‘A\xC3\x9f‘ for key 1

    这些信息被组合后返回消息到客户端,服务器将其从utf8转换成character_set_results系统变量所指定的字符集,如果 character_set_results变量值为空或binary,那么就不会发生转换操作,当然如果该变量设置的值就是UTF8也不会发生转换。 

    如果信息中的字符串,不能被以character_set_results变量中所指定的字符集展示,那么转换过程中可能就会触发另外的编码方案: 

  • 字符在基本多文种平面(Basic Multilingual Plane、BMP,也即Unicode编码的0号平面)范围0x0000OxFFFF区间的使用n\nnnnn标记输出。 

  • 字符不在BMP范围0x01000OxlOFFFF区间的使用n\+nnnnnnn标识输出。 

设置错误信息的语言

    默认情况下,mysqld进程会使用英文返回错误信息,这当然不代表它只能以英文显示,实现上它还支持其他很多种语言,包括 Czech、Danish、Dutch、Estonian、French、German、 

Greek、Hungarian、Italian、Japanese、Korean、Norwegian、Norwegian-ny、Polish、Portuguese、 Romanian、Russian、Slovak、Spanish或者Swedish,用户可以选择上面提到的任意一种语言来显示错误信息,遗憾的是目前还不支持中文。

如何设置错误信息的显示语言呢?

    MySQL服务在启动时,会读取--lc_messages_dir选项的值,并会在该选指定的路径下查找错误信息对应的语言文件。该选项的默认路径是MySQL软件安装目录下的share目录。例如:

[mysql@lee ~]$ ll /usr/local/mysql/share/
总用量 1424
drwxr-xr-x. 2 mysql mysql   4096 5月   1 22:51 aclocal
drwxr-xr-x. 2 mysql mysql   4096 5月   1 22:51 bulgarian
drwxr-xr-x. 2 mysql mysql   4096 5月   1 22:51 charsets
drwxr-xr-x. 2 mysql mysql   4096 5月   1 22:51 czech
drwxr-xr-x. 2 mysql mysql   4096 5月   1 22:51 danish
-rw-r--r--. 1 mysql mysql  25575 7月   3 2013 dictionary.txt
drwxr-xr-x. 2 mysql mysql   4096 5月   1 22:51 dutch
drwxr-xr-x. 2 mysql mysql   4096 5月   1 22:51 english
-rw-r--r--. 1 mysql mysql 503623 7月   3 2013 errmsg-utf8.txt
drwxr-xr-x. 2 mysql mysql   4096 5月   1 22:51 estonian
-rw-r--r--. 1 mysql mysql 699282 7月   3 2013 fill_help_tables.sql
drwxr-xr-x. 2 mysql mysql   4096 5月   1 22:51 french
drwxr-xr-x. 2 mysql mysql   4096 5月   1 22:51 german
drwxr-xr-x. 2 mysql mysql   4096 5月   1 22:51 greek
drwxr-xr-x. 2 mysql mysql   4096 5月   1 22:51 hungarian
-rwxr-xr-x. 1 mysql mysql   3963 7月   3 2013 innodb_memcached_config.sql
drwxr-xr-x. 2 mysql mysql   4096 5月   1 22:51 italian
drwxr-xr-x. 2 mysql mysql   4096 5月   1 22:51 japanese
drwxr-xr-x. 2 mysql mysql   4096 5月   1 22:51 korean
-rw-r--r--. 1 mysql mysql   1695 7月   3 2013 mysql_security_commands.sql
-rw-r--r--. 1 mysql mysql   3506 7月   3 2013 mysql_system_tables_data.sql
-rw-r--r--. 1 mysql mysql  92882 7月   3 2013 mysql_system_tables.sql
-rw-r--r--. 1 mysql mysql  10375 7月   3 2013 mysql_test_data_timezone.sql
drwxr-xr-x. 2 mysql mysql   4096 5月   1 22:51 norwegian
drwxr-xr-x. 2 mysql mysql   4096 5月   1 22:51 norwegian-ny
drwxr-xr-x. 2 mysql mysql   4096 5月   1 22:51 polish
drwxr-xr-x. 2 mysql mysql   4096 5月   1 22:51 portuguese
drwxr-xr-x. 2 mysql mysql   4096 5月   1 22:51 romanian
drwxr-xr-x. 2 mysql mysql   4096 5月   1 22:51 russian
drwxr-xr-x. 2 mysql mysql   4096 5月   1 22:51 serbian
drwxr-xr-x. 2 mysql mysql   4096 5月   1 22:51 slovak
drwxr-xr-x. 2 mysql mysql   4096 5月   1 22:51 spanish
drwxr-xr-x. 2 mysql mysql   4096 5月   1 22:51 swedish
drwxr-xr-x. 2 mysql mysql   4096 5月   1 22:51 ukrainian

    还有一个选项--lc_messages, 这个选项就是用来指定错误信息的语言。

    lc_messages_dir是个只读的系统变量,MySQL服务启动后就无法修改,它只是指定路径而己,决定语言的lc_messages系统变量则可以在MySQL服务运行时随意修改,并且既可以在全局粒度修改,也可以在会话粒度修改。

    修改当前错误信息的语言为法文,即修改当前会话中lc_messages系统变量的值,执行命令如下:

(system@localhost)[leedb]> set lc_messages=fr_FR;
Query OK, 0 rows affected (1.81 sec)

触发个错误看看:

(system@localhost)[leedb]> select abc;
ERROR 1054 (42S22): Champ abc inconnu dans field list

   上面提到的两个系统变量lc_messages_dir和lc_messages是从MySQL 5.5 版本才开始引入的,在之前的版本中,要设置语言是通过--language选项,该参数相当于-lc_messages_dir和-lc_messages的集合,比如说,仍然设置法语显示,则在MySQL 5.5之前的版本中,需要在启动时加载-language选项,执行命令如下:

$ mysqld safe --language=/usr/local/mysql55/share/french


3、国家字符集

    MySQL中还存在NCHAR、NVARCHAR这样的字符类型,这其中的N代表的就是NATIONAL,这类字符类型在MySQL数据库中拥有固定的字符集设置,在MySQL 5.6版本中,使用utf8作为这种类型在存储时的字符集。

    也就是说,在MySQL 5.6版本中,不管如何设置字符集,当使用N[char/varchar/text] 数据类型时,这些列的字符集均为utf8.这也是它被称为“国家字符集”的原因,拥有更好的兼容性,不管所使用的字符究竟是何种,均能够被正确支持和保存。 

    基于这一点,下面几种列的字义在功能上是完全相同的:

CHAR(10) CHARACTER SET utf8 

NATIONAL CHARACTER(10)

NCHAR(IO)



本文出自 “Lee” 博客,转载请与作者联系!

【MySQL管理维护-第5章】MySQL字符集三

标签:mysql   字符集   

原文地址:http://leexide.blog.51cto.com/6459431/1641733

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!