mysql set names中文乱码_mysql中文乱码解析

相信大家在开发后台的过程中都遇到过中文乱码的问题,今天我就来讲讲其中的原因。

我这建了3张表,test_latin1,test_utf8,test_gbk,表结构如下

+-------+----------+------+-----+---------+-------+

| Field | Type     | Null | Key | Default | Extra |

+-------+----------+------+-----+---------+-------+

| name  | char(32) | YES  |     | NULL    |       |

+-------+----------+------+-----+---------+-------+

我的前端是gbk的编码

执行下面的语句

set names 'latin1'

insert into test_latin1 set name='王';('王'字是GBK编码)

select name from test_latin1;

结果是否为乱码?

执行下面的语句set names 'gbk'

insert into test_latin1 set name='王';('王'字是GBK编码)

select name from test_latin1;

结果是否为乱码?

执行下面的语句

set names 'latin1'

insert into test_utf8 set name='王';('王'字是GBK编码)

select name from test_utf8 ;

结果是否为乱码?

我们举个例子,假设一个汉字的字符编码为0xFFFF,它在屏幕上能够正常显示,如果汉字存入数据库的时候和从数据库中取出的时候,编码一致,那么它肯定不是乱码。反过来,如果输出的时候是乱码,那么它肯定被转码了,至于为什么被转码了,我们得看看mysql里面做了什么(mysql难道会把无码片变成了有码片?)

首先mysql里面有2个概念,一个叫character set,一个叫collation。我们先说说character set。字符集就是数字,英文字符,汉字等编码格式,我们常见的是utf8,gbk,gb2312。mysql里面比较复杂,有4个东西跟它有关,分别是character_set_client,character_set_connection,character_set_database,character_set_results。set names (latin1)其实就是character_set_client=latin1,character_set_connection=latin1,character_set_results=latin1,它的流程是character_set_client ==> character_set_connection ==> Table Character ==> character_set_results。

我们按照上面的流程,来分析第一个问题。

set names 'latin1'----执行了character_set_client=latin1,character_set_connection=latin1,character_set_results=latin1;

insert into test_latin1 set name='王';这句话,mysql做了什么事呢?首先,character_set_client,它会把王字的编码当成latin1的编码传递给character_set_connection(此时不会转码),character_set_connection会把编码传递给Table Character,因为表本身是latin1,所以此时也不需要转码,select name from test_latin1;mysql会把test_latin1中的编码传递给前端,此时也不需要转码,所以,走个流程下来,我们输入的是什么编码,输出的还是相同的编码,因此,第一个问题的答案是不会是乱码。我画个流程图latin1==>latin1==>latin1==>latin1,没有转码的过程

我们在来看第二个问题。

set names 'test_gbk'----执行了character_set_client=gbk,character_set_connection=gbk,character_set_results=gbk;

insert into test_latin1 set name='王';character_set_client,它会把王字的编码当成gbk的编码传递给character_set_connection(此时不会转码),character_set_connection会把编码传递给Table Character,因为表是lanti1的编码格式,这个过程的时候就会进行转码,但是latin1的字符集小于gbk的字符集,所以它会找不到对应字符的编码,此时会以?代替。select name from test_latin1,此时会从latin1转码成gbk,但是此时latin1已经是错误的数据了,所以得到的gbk编码也是错误的了。流程gbk==>gbk==>latin1==>gbk,其中gbk==>latin1出了问题,我们select出来的数据也就不可能是输入时候的数据了。因此,这个问题的答案是乱码。

第三个。

set names 'test_latin1'

insert into test_utf8 set name='王';character_set_client,它会把王字的编码当成latin1的编码传递给character_set_connection(此时不会转码),character_set_connection会把编码传递给Table Character,此时表是utf8的格式,因此会进行转码,latin1==>utf8,因为utf8的字符集>latin1字符集,因此,转码正常。select name from test_utf8;会从utf8转码成latin1,此时可以转码成功,因此我们最终得到的和输入的时候是一致的,因此答案不是乱码。流程latin1==>latin1==>utf8==>latin1,从小的字符集到大的字符集再到小的字符集,转码是不会有问题的。

屁话了这么多,无非想告诉大家一个万精油方法,表创建的字符集和set names都设置成同一个字符集,就基本可以满足输入数据不会在转换过程中失真,也就是说输入是什么,输出就是什么。建议有中文的都设置成utf8字符集,一劳永逸。

posted on 2012-11-26 19:56 梨树阳光 阅读(2349) 评论(2)  编辑 收藏 引用 所属分类: 数据库

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值