天天看点

mySQL4.1以上版本数据库乱码问题彻底研究

看到不少用户反映转换完以后是乱码的情况,出现这种现象的主要原因是这类用户使用的都是mysql4.1以上的版本.下面作一个说明,希望出现这个问题的朋友都能耐心的把这个文档看完!!!

原理

注意:本文档只对mysql 4.1及以上的数据库版本有效,之前的mysql版本,由于没有提供对字符集的完整支持,因此也不存在此类问题。

mysql 4.1开始,对多语言的支持有了很大变化 (这导致了问题的出现)。尽管大部分的地方 (包括个人使用和主机提供商),mysql 3、4.0 仍然占主导地位;但 mysql 4.1 是 mysql 官方推荐的数据库,已经有主机提供商开始提供并将会越来越多;因为 latin1 在许多地方 (下边会详细描述具体是哪些地方) 作为默认的字符集,成功的蒙蔽了许多 php 程序的开发者和用户,掩盖了在中文等语言环境下会出现的问题。

mysql 4.1 对于字符集的指定可以细化到一台机器上安装的 mysql,其中的一个数据库,其中的一张表,其中的一栏,应该用什么字符集。但是,传统的 web 程序在创建数据库和数据表时并没有使用那么复杂的配置,它们用的是默认的配置,那么,默认的配置从何而来呢?

编译 mysql 时,指定了一个默认的字符集,这个字符集是 latin1;

安装 mysql 时,可以在配置文件 (my.ini) 中指定一个默认的的字符集,如果没指定,这个值继承自编译时指定的;

启动 mysqld 时,可以在命令行参数中指定一个默认的的字符集,如果没指定,这个值继承自配置文件中的;

此时 character_set_server 被设定为这个默认的字符集;

当创建一个新的数据库时,除非明确指定,这个数据库的字符集被缺省设定为 character_set_server;

当选定了一个数据库时,character_set_database 被设定为这个数据库默认的字符集;

在这个数据库里创建一张表时,表默认的字符集被设定为 character_set_database,也就是这个数据库默认的字符集;

当在表内设置一栏时,除非明确指定,否则此栏缺省的字符集就是表默认的字符集;

这个字符集就是数据库中实际存储数据采用的字符集,mysqldump 出来的内容就是这个字符集下的;

想要进行“正确”的存储和得到“正确”的结果,最方便的是在所有query开始之前执行一下:

set names 'gbk';

其中gbk是数据库字符集。

常见问题解决方案

我的数据使用latin1或其他编码存储中文信息,但phpmyadmin中中文为乱码

这问题是由于新版本的phpmyadmin都是强制使用正确的字符集进行数据库连接和显示的,因此如果存储内码和实际内码不一致,phpmyadmin是无法识别的。对于简体中文,phpmyadmin可识别gbk/utf8;繁体中文,可识别big5/utf8。如果你确定想使用这种“不正确”的字符集(事实上通常在mysql 4.1之前大家都是用“不正确”的字符集存储数据的)存储中文论坛数据,那么请使用phpmyadmin 2.5.x的老版本,他会使用最老和最普通的方式连接数据库,这样便可以正常管理。

我的论坛原来使用discuz! 4.0.0 rc版本+mysql 4.1没有问题,但升级到正式版后就有了乱码

浏览这问题前请您先看一下上一个问题的解答,您的情况和上面的情况差不多。rc版本使用“最老和最普通的方式”连接数据库,因此你如果使用“不正确”的字符集存储,事实上是没有问题的,但discuz! 4.0.0正式版使用了与phpmyadmin新版本相同的“正确”的数据库字符集,因此导致原来“不正确”的存储和“正确”的连接产生冲突,进而发生乱码。

解决此类问题,有如下两种方案:

更改存储字符集

主要的思想就是把数据库的字符集有latin1改为gbk,big5,或者utf8; 以下操作必须拥有主机权限。假设当前操作的数据库名为:database

导出

首先需要把数据导为mysql4.0的格式,具体的命令如下: mysqldump -uroot -p --default-character-set=latin1 --set-charset=gbk --skip-opt databse > test.sql

--default-characte-set 以前数据库的字符集,这个一般情况下都是latin1的,

--set-charset 导出的数据的字符集,这个可以设置为gbk,utf8,或者big5

导入

首先使用下面语句新建一个gbk字符集的数据库(test)

create database `test` default character set gbk collate gbk_chinese_ci;

然后把刚才导出的数据导入到当前的数据库中就ok了。

mysql -uroot -p --default-character-set=gbk -f test<test.sql

通过以上的导出和导入就把数据库的字符集改为正确的存储方式了。

总结:这种方案比较麻烦,但相对以后则一直都是使用mysql“正确”的方式进行存储和数据连接,并且新版本phpmyadmin不会乱码。

更改连接方式

discuz! 4.0.0

对于discuz! 4.0.0正式版,您可以找到./include/db_mysql.class.php,将

mysql_query("set names '".str_replace('-', '', $globals['charset'])."'");

前面加上“//”,即将其注释掉

discuz! 4.0.0+

对于discuz! 4.0.0以后的版本,已经支持在config.inc.php中使用单独的$dbcharset来设定数据库字符集,因此可根据您的实际情况选择留空(与$charset的设置相同),或指定为特定的数据库字符集(如latin1)

总结:折衷方案。数据使用“不正确”的内码存储,但显示和使用能够正常,phpmyadmin新版本乱码,老版本可用。备份和恢复时候需要特别注意字符集问题。

应当如何升级mysql 4.0的数据到mysql 4.1+中

如果数据文件中有中文信息,那么将mysql 4.0的数据文件,直接拷贝到mysql 4.1中就是不可以的,即便在my.ini中设置了default-character-set为正确的字符集。虽然貌似没有问题,但mysql 4.1的字符集有一处非常恼人的地方,以gbk为例,原本mysql 4.0数据中varchar,char等长度都会变为原来的一半,这样存储中文容量不变,而英文的存储容量就少了一半。这是直接拷贝数据文件带来的最大问题。

所以,升级的根本,如果想使用“正确”的字符集,还是先用mysqldump导出成文件,然后导入。

至于如果原来用的latin1,现在在mysql 4.1中还想继续“错误的”使用latin1,那么只需把default-character-set设置为latin1,并且在论坛中更改连接方式即可,这样的情况是可以直接拷贝数据文件的。