首页 > 代码库 > MySQL字符集乱码

MySQL字符集乱码

什么是字符集?

    字符集是一套符号和编码的规则,可以想象为二进制位和符号的转换表。


MySQL支持的字符集

    MySQL数据库可以支持多种字符集。

    MySQL字符集包括字符集(character set)和校对规则(collation)两个概念。字符集是用来定义MySQL存储字符串的方式,校对规则则是用来定义了比较字符串的方式。字符集和校对规则是一对多的关系。

    每个字符集至少对应一个校对规则。

# 查看支持的字符集
mysql> SHOW CHARACTER SET;
# 查看支持的校对规则
mysql> SHOW COLLATION;


    MySQL字符集设置非常灵活,分别可以在服务器级、数据库级、表级、字段级设置。

数据库对象的字符集的指定有如下继承关系:

Server -> Database -> Table -> Column

也就是说,如果某一级没有显示指定字符集,那么将继承上一级的字符集。

# 查看服务器字符集相关的系统变量
mysql> SHOW VARIABLES LIKE ‘%char%‘;

wKioL1SQVebgKuIHAANaVutXzkI147.jpg


乱码问题?

MySQL处理连接时,外部连接发送过来的SQL请求会根据以下顺序进行转换:
character_set_client           //客户连接所采用的字符集
|
character_set_connection  //MySQL连接字符集
|
character_set_database    //数据库所采用的字符集(表,列)
|
character_set_results        //返回的结果所采用的字符集

  1. 我们告诉服务器,我发送给你的数据是什么编码? character_set_client

  2. 如果发现和连接器指定的编码不一致,要转换为什么编码? character_set_connection

  3. 查询的结果用什么编码? character_set_results

如果以上三者都为字符集N,可简写为: set names N;

下面通过实例来演示为什么会乱码?

# 创建一个表
mysql> CREATE TABLE person (
    -> id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    -> name VARCHAR(30)
    -> ) DEFAULT CHARSET utf8;
# 然后执行下面3条命令, 可以简写为 set names utf8;
set character_set_client=utf8;
set character_set_connection=utf8;
set_character_set_results=utf8;
# 查看当前字符集设置
mysql> show variables like ‘%char%‘;
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       |
| character_set_connection | utf8                       |
| character_set_database   | latin1                     |
| character_set_filesystem | binary                     |
| character_set_results    | utf8                       |
| character_set_server     | latin1                     |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
# 然后插入一条数据
mysql> INSERT INTO person(name) VALUES(‘中文‘);
# 查询
mysql> SELECT * FROM person;
+----+--------+
| id | name   |
+----+--------+
|  1 | 中文   |
+----+--------+
# 显示结果是正常的。

# 好,接下来,我们改变character_set_results 为 gbk
mysql> set character_set_results=gbk;
Query OK, 0 rows affected (0.04 sec)

mysql> SELECT * FROM person;
+----+------+
| id | name |
+----+------+
|  1 |      |
+----+------+

产生乱码的根本原因就是:

各字符集系统变量不一致,导致进行字符集转换。


    比如说:客户机没有正确地设置client字符集,导致原先的SQL语句被转换成connection 所指字符集,而这种转换,可能是会丢失信息的,如果client是utf8格式,那么如果转换成gb2312格式,这其中必定会丢失信息,反之则不会丢失。一 定要保证connection的字符集大于client字符集才能保证转换不丢失信息。同理,connection与results也是这样。就像编程语言中的数据类型相互转换时一样,比如把double类型强制转换成int类型,就会造成精度的丢失一样。

    我们来仔细说明一下转换的过程:

  • 向默认字符集为utf8的数据表插入utf8编码的数据前没有设置连接字符集,查询时设置连接字符集为utf8
         – 插入时根据MySQL服务器的默认设置,character_set_client、character_set_connection和character_set_results均为latin1;
         – 插入操作的数据将经过latin1=>latin1=>utf8的字符集转换过程,这一过程中每个插入的汉字都会从原始的3个字节变成6个字节保存;
         – 查询时的结果将经过utf8=>utf8的字符集转换过程,将保存的6个字节原封不动返回,产生乱码。

  • 向默认字符集为latin1的数据表插入utf8编码的数据前设置了连接字符集为utf8
         – 插入时根据连接字符集设置,character_set_client、character_set_connection和character_set_results均为utf8;
         --插入数据将经过utf8=>utf8=>latin1的字符集转换,若原始数据中含有\u0000~\u00ff范围以外的 Unicode字符,会因为无法在latin1字符集中表示而被转换为“?”(0×3F)符号,以后查询时不管连接字符集设置如何都无法恢复其内容了。

综上,终极解决方案如下:
1.首先要明确你的客户端时候何种编码格式,这是最重要的(IE6一般用utf8,命令行一般是gbk,一般程序是gb2312)
2.确保你的数据库使用utf8格式,很简单,所有编码通吃。
3.一定要保证connection字符集大于等于client字符集,不然就会信息丢失,比如: latin1 < gb2312 < gbk < utf8,若设置set character_set_client = gb2312,那么至少connection的字符集要大于等于gb2312,否则就会丢失信息
4. 以上三步做正确的话,那么所有中文都被正确地转换成utf8格式存储进了数据库,为了适应不同的浏览器,不同的客户端,你可以修改 character_set_results来以不同的编码显示中文字体,由于utf8是大方向,因此web应用是我还是倾向于使用utf8格式显示中文 的。


总结
    根据上面的分析和建议,我们解决我们遇到问题应该使用什么方法大家心里应该比较清楚了。对,就是在创建database的时候指定字符集,不要去通过修改默认配置来达到目的,当然你也可以采用指定表的字符集的形式,但很容易出现遗漏,特别是在很多人都参与设计的时候,更容易纰漏。



http://www.cnblogs.com/zzwlovegfj/archive/2012/06/25/2560649.html

http://www.cnblogs.com/discuss/articles/1862248.html


本文出自 “Share your knowledge” 博客,请务必保留此出处http://skypegnu1.blog.51cto.com/8991766/1591215

MySQL字符集乱码