设为首页 收藏本站
查看: 517|回复: 0

[经验分享] MySQL字符集乱码

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2014-12-18 08:38:32 | 显示全部楼层 |阅读模式
什么是字符集?
    字符集是一套符号和编码的规则,可以想象为二进制位和符号的转换表。

MySQL支持的字符集
    MySQL数据库可以支持多种字符集。
    MySQL字符集包括字符集(character set)和校对规则(collation)两个概念。字符集是用来定义MySQL存储字符串的方式,校对规则则是用来定义了比较字符串的方式。字符集和校对规则是一对多的关系。
    每个字符集至少对应一个校对规则。
1
2
3
4
# 查看支持的字符集
mysql> SHOW CHARACTER SET;
# 查看支持的校对规则
mysql> SHOW COLLATION;




    MySQL字符集设置非常灵活,分别可以在服务器级、数据库级、表级、字段级设置。
数据库对象的字符集的指定有如下继承关系:
Server -> Database -> Table -> Column
也就是说,如果某一级没有显示指定字符集,那么将继承上一级的字符集。
1
2
# 查看服务器字符集相关的系统变量
mysql> SHOW VARIABLES LIKE '%char%';



wKioL1SQVebgKuIHAANaVutXzkI147.jpg

乱码问题?

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;
下面通过实例来演示为什么会乱码?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# 创建一个表
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的字符集转换,若原始数据中含有~?范围以外的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的时候指定字符集,不要去通过修改默认配置来达到目的,当然你也可以采用指定表的字符集的形式,但很容易出现遗漏,特别是在很多人都参与设计的时候,更容易纰漏。



运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-38218-1-1.html 上篇帖子: Mysql 主从复制实验 下篇帖子: Oracle SQL Developer 连接 MySQL
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表