`
xiegs2007
  • 浏览: 16127 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
文章分类
社区版块
存档分类
最新评论

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)

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

可见,这里character_set_client=gbk,character_set_connection=latin1,character_set_database=gbk。首先,client到connection过程中,汉字被转换成乱码(这个过程可能就会丢失信息);然后存储数据的时候,又从connection到存储的字符集(gbk)发生一次转换,乱码被转换成“更”乱码。这里如果connection与client的字符集有种包容性关系的话,如character_set_client=gbk, character_set_connection=utf8,character_set_results=gbk,底层存储也是gbk编码,由于utf8“兼容”所有的字符集,故在转换过程中不会发生信息丢失,查询的时候也不会是乱码,如下:

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

mysql> create table t (a varchar(10)) charset=gbk;
Query OK, 0 rows affected (0.05 sec)

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

mysql> select * from t;
+------+
| a    |
+------+
| 中国 |
+------+
1 rows in set (0.00 sec)

我来解释一下这个过程,假设“中国”的gbk编码是1234,而utf8的编码是4321,utf8的编码为1234的假设是“淘宝”。client的“中国”的编码1234进入connection,仍然是1234(但实际上它的含义已经发生变化为“淘宝”),存储的时候connection的1234编码到表存储也是1234,刚好正确表达了“中国”的意思,查询返回时,由于results也是gbk,所以不发生转换,正确显示。很显然,如果results又是一种与gbk不兼容的字符集如latin1,查询又会出问题,如下:

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

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

当我们改变底层存储的字符集的时候,会怎样?请看如下实验:

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

mysql> create table t (a varchar(10)) charset=latin1;
Query OK, 0 rows affected (0.05 sec)

mysql> insert into t values("淘宝");
Query OK, 1 row affected, 1 warning (0.02 sec)

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

很显然,由于latin1字符集无法存储汉字,故出现乱码。
下面,我们只改变results字符集,看看效果如何:

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

mysql> create table t (a varchar(10)) charset=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)

很显然,底层为gbk编码的字符串转换成latin1的字符集的字符,变成乱码,传给客户端,再次转换成gbk字符集,变成“更”乱码,故显示乱码。

下面,我再介绍几个“简约”命令。
SET NAMES ‘x’,(SET NAMES ‘charset_name’ COLLATE ‘collation_name’)相当于:

SET character_set_client = x;
SET character_set_results = x;
SET character_set_connection = x;

实验如下:

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

mysql> set names "ascii";
Query OK, 0 rows affected (0.00 sec)

mysql> show variables like "char%";
+--------------------------+----------------+
| Variable_name            | Value          |
+--------------------------+----------------+
| character_set_client     | ascii          |
| character_set_connection | ascii          |
| character_set_results    | ascii          |
| .........................| ......         |
+--------------------------+----------------+

SET CHARACTER SET ‘x’,相当于:

SET character_set_client = x;
SET character_set_results = x;
SET collation_connection = @@collation_database;

这里collation_connection = @@collation_database的意思就是把collation_connection的设置的collation_database的值,由于collation肯定能确定character set,故其又相当于多做了个设置:把character_set_connetion设置成character_set_database的值。请看如下实验:

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 "collat%";
+----------------------+-------------------+
| Variable_name        | Value             |
+----------------------+-------------------+
| collation_connection | latin1_swedish_ci |
| collation_database   | gbk_bin           |
| collation_server     | latin1_swedish_ci |
+----------------------+-------------------+
3 rows in set (0.00 sec)

mysql> set character set "ascii";
Query OK, 0 rows affected (0.00 sec)

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

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

通过以上的介绍,所以为了防止出现乱码,我们可以把character_set_client,character_set_connection,character_set_database,character_set_results设置成同样的值,把collation_connection和collation_database也设置成同样的值,这样就“一劳永逸”了。程序连接mysql的时候,一般都会显示设置character_set_client的值,如java连接中,一般都有如下的一段代码来显示设置这个值:

jdbc:mysql://10.1.6.174:3306/notify?connectTimeout=1000&characterEncoding=utf8

--EOF--

分享到:
评论

相关推荐

    解决MYSQL数据库乱码问题

    乱码问题是使用Navicat连接MySQL数据库时较为常见的问题之一。通过上述方法,我们可以有效地定位乱码的原因,并采取相应的措施解决问题。需要注意的是,在调整字符集设置时一定要谨慎操作,避免因误操作而造成数据...

    在DELPHI中使用MyDAC连接MySQL数据库时中文显示乱码的解决方法

    ### 在DELPHI中使用MyDAC连接MySQL数据库时中文显示乱码的解决方法 #### 背景介绍 在软件开发过程中,特别是涉及到多语言环境的应用程序开发时,字符编码问题常常成为开发者需要解决的一个重要问题。对于使用...

    c#解决mysql乱码问题的解决及mysql数据库操作的封装

    在C#编程中,与MySQL数据库交互时可能会遇到编码问题,导致数据乱码。这个问题通常是由于编码不一致或设置不当造成的。本篇文章将详细介绍如何解决MySQL数据库中的乱码问题,并探讨如何通过C#进行数据库操作的封装,...

    MySQL数据库—乱码总结

    #### 三、乱码原因及解决方案 ##### 3.1 数据库层面的字符集设置 **问题描述**:在安装MySQL数据库时,默认情况下可能没有正确配置字符集,导致后续的数据处理中出现乱码。 **解决方法**: 1. **修改配置文件**...

    pbootcms数据sqlite转mysql数据库

    标题 "pbootcms数据sqlite转mysql数据库" 涉及的是一个常见的数据库迁移过程,从SQLite数据库系统转换到MySQL数据库系统。这个过程在网站或应用的开发和维护中经常遇到,尤其是在更换数据库服务或者需要更强大的...

    ASP连MySQL数据库乱码问题

    本问题聚焦于ASP(Active Server Pages)与MySQL数据库进行数据操作时遇到的乱码问题。这通常涉及到字符编码不一致、设置不当或者传输过程中的编码转换错误。下面我们将深入探讨这个主题,以及如何解决这类问题。 ...

    MySQL数据库系统中文乱码问题及解决方案.pdf

    MySQL数据库系统中文乱码问题及解决方案 MySQL数据库系统中文乱码问题是指在使用MySQL数据库系统时,中文字符在存储、传输和显示过程中出现乱码的问题。这种问题的出现是由于字符集和编码方式的不兼容所致。 在...

    MySQL乱码解决方案数据库乱码

    #### 一、MySQL乱码背景及原因分析 在处理MySQL数据库时,遇到字符集编码不一致导致的数据乱码问题非常常见。这不仅会影响数据的正确显示,还可能导致数据丢失或损坏。根据提供的标题、描述、标签以及部分内容来看...

    linux下mysql数据库乱码问题

    ### Linux 下 MySQL 数据库乱码问题详解 #### 一、问题背景及原因分析 在 Linux 系统中使用 MySQL 数据库时,可能会遇到字符集不匹配导致的数据乱码问题。通常这种现象表现为数据库中的文本数据无法正确显示或存储...

    使用MySQL Migration Toolkit数据迁移工具迁移SqlServer 2005精简版数据库到mysql数据库乱码的问题

    使用MySQL Migration Toolkit数据迁移工具迁移SqlServer 2005精简版数据库到mysql数据库乱码的问题,使用ACCESS数据库编辑转换迁移

    让MySql彻底支持中文_解决mysql数据库乱码

    "让MySql彻底支持中文_解决mysql数据库乱码"这个主题聚焦于如何确保MySQL正确地存储和显示中文字符,避免出现乱码情况。这通常涉及到MySQL服务器的配置、数据表的编码设置以及客户端连接的字符集设定。 首先,我们...

    h2数据导入mysql数据库(看评论酌情下载)

    h2 数据库导入 MySQL 数据库 h2 数据库导入 MySQL 数据库是指将 h2 数据库中的数据导入到 MySQL 数据库中,以便更好地存储和管理数据。下面将详细介绍 h2 数据库导入 MySQL 数据库的步骤。 首先,需要创建一个 ...

    Kettle推送数据到Mysql数据库表时乱码.docx

    乱码原因 -------- 在 Kettle 中进行数据抽取时,如果抽取的源数据库和目标数据库不是同一个数据库,可能会导致转换后的中文出现乱码情况。这种情况的原因是由于在中文环境下有的数据库客户端默认编码格式是 UTF-8...

    mysql数据库乱码问题.pdf

    MySQL数据库中的乱码问题是一个常见的技术难题,尤其在处理多语言环境或者跨平台的数据交互时。乱码通常出现在数据的存储、检索或者显示过程中,这可能是由于编码设置不一致所导致的。以下是一些关于如何解决MySQL...

Global site tag (gtag.js) - Google Analytics