首页 > 代码库 > 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%‘;
乱码问题?
MySQL处理连接时,外部连接发送过来的SQL请求会根据以下顺序进行转换:
character_set_client //客户连接所采用的字符集
|
character_set_connection //MySQL连接字符集
|
character_set_database //数据库所采用的字符集(表,列)
|
character_set_results //返回的结果所采用的字符集
我们告诉服务器,我发送给你的数据是什么编码? character_set_client
如果发现和连接器指定的编码不一致,要转换为什么编码? character_set_connection
查询的结果用什么编码? 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字符集乱码