日期:2016-7-13(原创文章,禁止转载)
2009-03-06 15:27
来源:IT168
编辑:Googler【纠错】人评论
A-A+
怎样开淘宝店 站优化方法 创业如何取得投资
小米note顶配版评测
最新LOL活动
1、概述
公司新购了一批PC,准备把几个性能较优的PC升级为数据库服务器,替换老旧的机器。公司有套POS终端软件,后台数据存储是 MySQL 3.23 版。我准备硬件升级的同时升级数据库软件。但是升级进程中遇到闻名的 MySQL 的乱码问题。经过查找资料,加上自己的摸索和经验,终究完善地解决这个问题。
MySQL 的乱码问题(不单单包括中文乱码,也包括其它语言的乱码,以下称之为乱码问题)只存在于4.1及其以上版本。4.1之前的 MySQL 不支持多语言,所以它会将你给它的数据原封不动地保存,再原封不动地读出来。从字节的角度来看,数据在这1进程中不会产生任何变化,因此不会有乱码。
4.1及以后的版本开始支持多语言,这个所谓的多语言,就是在输入输出时 MySQL 会替你做编码转换。而这个转换规则就是由客户端编码和服务器端编码来决定的癫痫病的发作。
编码转换的规则就是,在输入数据时将编码由客户端编码转换为服务器端编码,输出时将数据由服务器端编码转换为客户端编码。
2、乱码产生缘由
MySQL 字符编码是版本4.1引入的,支持多国语言,而且一些特性已超过了其它大多数数据库管理系统呼和浩特哪家看癫痫病最好。正由于这1特性才致使 MySQL 的乱码问题。
字符集是一套符号和编码。校订规则是在字符集内用于比较字符的一套规则。让我们使用一个假想字符集的例子来区分清楚。
假定我们有一个字母表使用了四个字母:A、B、a、b。我们为每一个字母赋予一个数值:A=0,B= 1,a= 2,b= 3。字母A是一个符号,数字0是A的编码,这四个字母和它们的编码组合在一起是一个字符集。
假定我们希望比较两个字符串的值(在ifelse语句中我们常常做值的比较):A和B。比较的最简单的方法是查找编码:A为0,B为1。由于0 小于1,我们可以说A小于B。我们做的仅仅是在我们的字符集上运用了一个校订规则。校订规则是一套规则(在这种情况下仅仅是一套规则):对编码进行比较。我们称这类全部可能的规则中的最简单的校订规则为一个binary(二元)校订规则。
但是,如果我们希望小写字母和大写字母是等价的,应当怎样?那末,我们将最少有两个规则:(1)把小写字母a和b视为与A和B等价;(2)然后比较编码。我们称这是一个大小写不敏感的校订规则。比二元校订规则复杂一些。
在实际生活中,大多数字符集有许多字符:不但仅是A和B,而是全部字母表,有时候有许多种字母表,或一个东方的(比如中文、日文、韩文、藏文、泰文等等)使用上千个字符的书写系统,还有许多特殊符号和标点符号。并且在实际生活中,大多数校订规则有许多个规则:不但仅是大小写不敏感,还包括重音符不敏感(重音符 是附属于一个字母的符号,象德语的?符号)和多字节映照(例如,作为规则?=OE就是两个德语校订规则的一种)。
(以上摘自MySQL 5.1 手册。更多内容可参见:://sql/doc/refman/5.1/zh/charset)
MySQL 4.1.x开始支持以下这些事情
l 使用多种字符集(Character Set)来存储字符
l 使用多种校订规则(Collation)来比较字符串
l 在同一台服务器、同一个数据库或乃至在同一个表中使用不同字符集或校订规则来混合字符串
l 允许定义任何级别的字符集和校订规则
MySQL 4.1及以上版本的字符集支持(Character Set Support)有两个方面:字符集(Character Set)和校订规则(Collation)。 字符集和校订规则有4个级别的默认设置:服务器(server),数据库(database),数据表(table)和连接(connection)。
MySQL 中是根据下面几个变量肯定服务器端和客户端用的甚么字符集:
character_set_client
客户端字符集
character_set_connection
客户端与服务器端连接采取的字符集
character_set_results
SELECT查询返回数据的字符集
character_set_database
数据库采取的字符集
MySQL的字符集处理是这样的:
1、发送要求。
1)客户端发送要求到服务器端。
2)服务器端会把要求的数据从客户端字符集(character_set_client)转成服务器连接字符集(character_set_connection)。
3)然後服务器会检测存储区域(table,column)的字符集,然后把数据从连接字符集(character_set_connection)转为存储区域(table,column)的字符集,然後再存储或查询。
2、返回要求。
1)服务器将存储区域(table,column)的字符集转换成服务器连接字符集(character_set_connection)。
2)将服务器连接字符集(character_set_connection)转换成结果字符集(character_set_results),再发送到客户端。
例如,我建立一个字符集为 gbk 的数据库(服务器端)。(MySQL 4.1 开始,在建立数据库时要指定它的字符集和校订规则,不指定就用默许的字符集和校订规则。)
连接数据库的程序(客户端)使用 gb2312 字符集(如 windows 命令行下使用 MySQL ,或 PHP 连接MySQL ),那末在履行 insert 命令时,insert 的字符串将做一个 gb2312 到 gbk 的转换。而 select 时,数据库中保存的数据会先经过 gbk 到 gb2312 的转换以后再给你(结果集)。
好,那末为何升级3.23(或4.0)到4.1时会乱码?举个例子说明。
例如3.23的数据库中保存的是gbk编码的数据。升级之前我将这些数据导出保存到文件里,这个文件的编码固然也是gbk的(由于3.23不支持多语言,不会对数据进行转换,也就是前面说的原封不动地保存,原封不动地读出)。
然后我在4.1中建立一个数据库,字符集为A;客户端字符集为B。将刚才的gbk数据导入。
1)A=gbk,B=gbk
导入数据时数据不会被转换;读出时需要set names gbk(set name命令下面将讲授)。
2)A=latin1,B=gbk
导入数据会进行gbk-latin1的转换,可能会丢失数据,产生乱码。
3)A=gbk太原治疗癫痫病医院,B=latin1
导入数据会进行latin1-gbk转换,可能会产生乱码。
4)A=latin1,B=latin1
导入数据时不会进行转换;读出时不需要set names gbk 。
大家可以看到,上面1)、4)才是正确的做法,即让A和B使用一样的字符集才不会乱码。
3、解决方案
了解了 MySQL 4.1.x 以上版本字符集处理的进程,我们就知道了怎样从原理上解决这个问题。
思路:让服务器端和客户端的字符集保持一致。
服务器端的编码是由字符集(Character Set)和校订规则(Collation)决定的。
上面提到,MySQL 中是根据下面几个变量肯定服务器端和客户端用的甚么字符集:
character_set_client
客户端字符集
character_set_connection
客户端与服务器端连接采取的字符集
character_set_results
SELECT查询返回数据的字符集
character_set_database
数据库采取的字符集
也就是说,只要保证这几个变量采取一致的字符集,就不会出现乱码问题了。
1
2
下一页
查看全文