日期:2014-05-16  浏览次数:20456 次

mysql数据库乱码的原因之链接通道(转)

这里首先需要解释的是,我想应该就是连接通道的含义了。那什么是连接通道呢?
所谓连接通道,就是客户端和服务器端保持连接的一个通道,它是逻辑上的一个概念。客户端通过连接通道发送sql语句到服务器端,服务端执行,将结果再通过连接通道返回至客户端。the connection is the pass when you connect to the server.

这个过程中,有几个临界点(逻辑上概念),是我们需要注意的,mysql也就在这几个临界点上做了文章。

1、当语句离开客户端的时候:
从客户端出来的,包括sql语句本身(这里里面就包含字符串和关键字等了),以及character_set_client系统变量。为什么要包含这个变量呢?这个变量的作用说明2点,也是它的作用:一是表示该语句中的字符集是使用character_set_client指定的字符集编码的,二是通过此系统变量来告诉服务器所发送来的语句中的字符集编码。
2、当服务器端接受到客户端的语句的时候:
mysql会使用character_set_connection/collation_connection指定的字符集以及校验规则,将客户端的字符串,做一个从character_set_client到character_set_connection的转换。
3、当服务器处理好结果以后,在把结果传给客户端前:
mysql会先将结果转换成character_set_results指定的字符集,然后传回给客户端。

?

当字符串在mysql服务器的时候,最终以什么格式存储到mysql数据库中,这个是受到具体的数据表级别、列级别字符集设置的控制了。

从上面的介绍中,我们就知道和连接通道相关几个参数了,他们分别是character_set_client/connection/results,可以如下查看:

mysql> show variables like "char%";
+--------------------------+-------------------+
| Variable_name? ? ? ? ? ? | Value? ? ? ? ? ? ?|
+--------------------------+-------------------+
| character_set_client? ? ?| latin1? ? ? ? ? ? |
| character_set_connection | latin1? ? ? ? ? ? |
| character_set_database? ?| gbk? ? ? ? ? ? ? ?|
| character_set_results? ? | latin1? ? ? ? ? ? |
| .........................| ......? ? ? ? ? ? |
+--------------------------+-------------------+
8 rows in set (0.00 sec)

mysql> show variables like "colla%";
+----------------------+-------------------+
| Variable_name? ? ? ? | Value? ? ? ? ? ? ?|
+----------------------+-------------------+
| collation_connection | latin1_swedish_ci |
| collation_database? ?| gbk_bin? ? ? ? ? ?|
| collation_server? ? ?| latin1_swedish_ci |
+----------------------+-------------------+
3 rows in set (0.00 sec)

下面我们来做个实验,来证明一下这个结果:
首先保证character_set_connection与character_set_results以及底层存储字符集的一致性,看看character_set_client的效果。

mysql> show variables like "char%";
+--------------------------+------------------+
| Variable_name? ? ? ? ? ? | Value? ? ? ? ? ? |
+--------------------------+------------------+
| character_set_client? ? ?| latin1? ? ? ? ? ?|
| character_set_connection | gbk? ? ? ? ? ? ? |
| character_set_database? ?| gbk? ? ? ? ? ? ? |
| character_set_results? ? | gbk? ? ? ? ? ? ? |
| .........................| ......? ? ? ? ? ?|
+--------------------------+------------------+
8 rows in set (0.00 sec)

mysql> create table t (a varchar(10));? --? 这里没有指定字符集,就默认使用了database的字符集gbk了
Query OK, 0 rows affected (0.08 sec)

mysql> insert into t values("中国");
Query OK, 1 row affected (0.00 sec)

mysql> select * from t;
+-------+
| a? ? ?|
+-------+
| ???ú |
+-------+
1 row in set (0.00 sec)

由此可以看到由于latin1与gbk对汉字的编码方式不一样(或者说latin1根本就不能正确编码汉字),在这个collection过程中,从character_set_client到character_set_connection转换时,就把你输入的好好的汉字转换成乱码了。那么,如果让过程不发生转换呢?

mysql> set character_set_client=gbk;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t values("人民");
Query OK, 1 row affected (0.02 sec)

mysql> select * from t;
+-------+
| a? ? ?|
+-------+
| ???ú |
| 人民? |
+-------+
2 rows in set (0.00 sec)

可见,这里是能正确存储和显示的,很简单,因为任何转换都没有发生,当然就不会出现乱码了。

接着做实验,我们让character_set_connection发生变化:

mysql> set character_set_connection=latin1;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t values ("共和国");
Query OK, 1 row affected (0.00 sec