mysql 4.1+ 汉字乱码问题研究 --安恒网管员手记
2005-09-15    刘世伟   
打印自: 安恒公司
地址: HTTP://www.anheng.com.cn/news/article.php?articleid=716
mysql 4.1+ 汉字乱码问题研究 --安恒网管员手记
在mysql4.1下,一些数据库里面的中文会出现??乱码现象.因为,4.1增加了对utf8的支持,这是件好事.但是,问题是大部分的程序,都是使用的gb2312/gbk这样的编码格式,如果把它们都改成utf8格式,要转换成utf8需要解决的事情比较多.编辑器,浏览器,mysql-server,mysql-client,php,php-mysql,cvs代码管理,数据库备份,还有合适的gb2312到utf8的转换工具.诸多的环节需要考虑.
数据库的格式转换,文件程序的格式转换,和mysql-server的设置情况记录一下.
当然真正的转换,现在还没有做,现在只是做点规划.

关于??乱码,是系统相关的各个环节之间进行代码转换出现的问题,比如在shell下用mysql这个程序对数据库进行恢复,mysql会错误的把代码进行转换,导致乱码出现,

在转换之前,我们一定要清楚,文件是什么格式,数据库内部是什么格式,都要统一到utf8下来,不对的要进行格式转换.

1.数据库的转换.
  以前数据库里面的字符,应该都是gb2312格式,这时,需要把所有的数据库文件导出成sql文本,然后对文本进行utf-8的格式转换.这里要注意的是一些2进值的字段内容会出问题.幸好,在我的项目中,2进值内容都进行了base64编码,如果数据库中存在2进值的内容,就要对它们进行单独的处理了.

  用mysqldump把数据从mysql4.0中导出,此时得到的sql文件应该是gb2312的,然后用iconv这个程序把sql文件改为utf8

导出一个mysql4.0的库(服务器:192.168.2.2 库名:dbname):
mysqldump -h 192.168.2.2 --add-drop-table -c   --set-charset=latin1 --allow-keywords --force -p  -u root dbname >1.sql
 内容转换utf8
iconv -c -f gb2312 -t utf8 1.sql -o 2.sql

在导入到4.1之前,先把mysql-server和mysql-client设置到utf8模式.

修改/etc/mysq1/my.cnf,在[mysqld]和[mysql]各增加1行:
[mysqld]
character_set_server = utf8
[mysql]
default-character-set =utf8
保证让服务器端和客户端都默认工作在utf8模式下,重启mysql-server后就可以导入了.
mysql -u root -h localhost test <2.sql
到这里,一个数据库就转换完成了.已经完全工作在utf8模式下了.

php的程序的修改.也可以用iconv程序.进行.
首先从cvs导出一个干净的代码拷贝,比如在net目录下,
cvs -d :pserver:xxx.xxx.xx.xx net co
删除一些不需要转换的文件
然后执行转换
find . -name "*.php" -type f -exec mv {} {}.old \; -exec iconv --verbose -f gb2312 -t utf8  {}.old  -o  {} \;  -exec  rm  {}.old   \;
至此,php代码就批量的转换到utf8模式.还有就是只要修改html的head的语言声明,从gb2312改成utf8,浏览器就会自动使用utf8的模式显示这个页面.  content="text/html; charset=utf8"

最后,就是把编辑器改成utf8模式了.这个就比较简单了.

好了,我们的web应用已经进入utf8模式了.哈哈.

实战

搞清楚了各种编码之后, 考虑到现在的文本编辑器还离不开gbk编码,

制定了如下的mysql升级方案:

mysql服务器存储使用utf8, mysql客户端使用gbk, html和php使用gbk,这样把应用移植到mysql 4.1+

现在的数据库的服务器存储格式是gbk, 直接把服务器换成utf8肯定会造成乱码.所以首先用mysqldump

把数据都导出成gbk的sql文本, 然后在mysql5.0下用utf8格式重建数据库,并导入.

1.导出所有的数据库.用mysqldump,此时,mysql-server是4.0,gbk编码:
mysqldump  --host=127.0.0.1   --default-character-set=latin1 --add-drop-table -c  --allow-keywords --force --password=!w@4d \
--user=root table1 >0.sql

先用gbk编码看一下0.sql,确认不是乱码, 再进行下面的操作

export LANG=zh_CN.GBK

vi 0.sql

正确导出的sql文件参考这么修改:

--- 0.sql       2010-02-25 11:23:00.000000000 +0800
+++ 1.sql       2010-02-25 11:26:04.000000000 +0800
@@ -7,7 +7,7 @@
 /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
 /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
 /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
-/*!40101 SET NAMES latin1 */;
+/*!40101 SET NAMES gbk */;
 /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
 /*!40103 SET TIME_ZONE='+00:00' */;
 /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
@@ -21,9 +21,9 @@

 DROP TABLE IF EXISTS `cdb_members`;
 SET @saved_cs_client     = @@character_set_client;
-SET character_set_client = gbk;
+SET character_set_client = gbk;
 CREATE TABLE `cdb_members` (
   `uid` int(10) NOT NULL auto_increment,
   `username` varchar(25) NOT NULL default '',
   `password` varchar(40) NOT NULL default '',
   `regdate` bigint(30) NOT NULL default '0',
@@ -59,7 +59,7 @@
   PRIMARY KEY  (`uid`),
   KEY `username` (`username`),
   KEY `status` (`status`)
-) ENGINE=MyISAM AUTO_INCREMENT=32767 DEFAULT CHARSET=latin1;
+) ENGINE=MyISAM AUTO_INCREMENT=32767 DEFAULT CHARSET=utf8;
 SET character_set_client = @saved_cs_client;

 --

2.升级服务器到5.0 设置\etc\mysql\my.cnf,

[client]
//客户端默认gbk编码
default-character-set =gbk
[mysqld_safe]
//服务器使用utf-8
character_set_server = utf8
[mysqld]
//服务器使用utf-8
character_set_server =utf8
[mysqldump]
//mysqldump使用 gbk (本地导出)
default-character-set =gbk
[mysql]
//mysql命令行使用gbk (本地导入)
default-character-set =gbk

3.用phpmyadmin等工具,或者直接用mysql命令行重新建立数据库

4.用mysql命令行导入备份的数据.

mysql -u root -p  --default-character-set=gbk table1 <1.sql

5.修改php程序,在每次联结数据库操作(mysql_connect())后面增加一句
   mysql_query("SET CHARACTER SET   gbk");

6.完成升级.

责任编辑: admin