看到不少用户反映转换完以后是乱码的情况,出现这种现象的主要原因是这类用户使用的都是mysql4.1以上的版本.下面作一个说明,希望出现这个问题的朋友都能耐心的把这个文档看完!!!
, D! H6 s- K- {5 b) W/ C& b原理
8 g& Y g+ P$ t, D1 o3 `注意:本文档只对MySQL 4.1及以上的数据库版本有效,之前的MySQL版本,由于没有提供对字符集的完整支持,因此也不存在此类问题。
8 m* V8 m$ z# J: O5 j' w) h
% a0 D" d2 w( v7 G, u, C2 zMySQL 4.1开始,对多语言的支持有了很大变化 (这导致了问题的出现)。尽管大部分的地方 (包括个人使用和主机提供商),MySQL 3、4.0 仍然占主导地位;但 MySQL 4.1 是 MySQL 官方推荐的数据库,已经有主机提供商开始提供并将会越来越多;因为 latin1 在许多地方 (下边会详细描述具体是哪些地方) 作为默认的字符集,成功的蒙蔽了许多 PHP 程序的开发者和用户,掩盖了在中文等语言环境下会出现的问题。
+ G* S! K6 X7 [, L/ P- W
/ x3 @: @) u, s1 D4 N0 sMySQL 4.1 对于字符集的指定可以细化到一台机器上安装的 MySQL,其中的一个数据库,其中的一张表,其中的一栏,应该用什么字符集。但是,传统的 Web 程序在创建数据库和数据表时并没有使用那么复杂的配置,它们用的是默认的配置,那么,默认的配置从何而来呢?
! c0 S' c% [+ G+ Z, z, S* a
8 ?. J7 r7 c+ [" f1 {编译 MySQL 时,指定了一个默认的字符集,这个字符集是 latin1;
" H* K* |# w6 t! J
安装 MySQL 时,可以在配置文件 (my.ini) 中指定一个默认的的字符集,如果没指定,这个值继承自编译时指定的;
& E7 m P1 V1 b0 @. N/ q- a! w
启动 mysqld 时,可以在命令行参数中指定一个默认的的字符集,如果没指定,这个值继承自配置文件中的;
' q4 c: b$ a* i9 \9 C
此时 character_set_server 被设定为这个默认的字符集;
1 m% T% t* j/ Q2 D: ? x! B当创建一个新的数据库时,除非明确指定,这个数据库的字符集被缺省设定为 character_set_server;
& c8 a2 L- @4 ] d9 D: w- z当选定了一个数据库时,character_set_database 被设定为这个数据库默认的字符集;
1 [3 o+ H: m, h& z$ W$ v
在这个数据库里创建一张表时,表默认的字符集被设定为 character_set_database,也就是这个数据库默认的字符集;
4 W; E- j8 Z' Z1 D( N8 q1 Y
当在表内设置一栏时,除非明确指定,否则此栏缺省的字符集就是表默认的字符集;
5 K# T, i: f) ~3 P
这个字符集就是数据库中实际存储数据采用的字符集,mysqldump 出来的内容就是这个字符集下的;
& H3 Y$ m) B6 C$ _1 H
想要进行“正确”的存储和得到“正确”的结果,最方便的是在所有query开始之前执行一下:
5 ]* N- V0 E$ i3 a& ?/ L
7 F m5 f3 O+ @% E1 P, U. @0 n
SET NAMES 'gbk';
4 P b/ T- R' x9 _0 k0 k其中gbk是数据库字符集。
* C( d6 t' y# [+ J) X- H* l1 q/ K- z$ S* D0 L0 c1 ]% P
常见问题解决方案
0 D4 a) E- y& a
我的数据使用latin1或其他编码存储中文信息,但phpMyAdmin中中文为乱码
- Q, |( ?2 K5 i+ T: f G8 j
这问题是由于新版本的phpMyAdmin都是强制使用正确的字符集进行数据库连接和显示的,因此如果存储内码和实际内码不一致,phpMyAdmin是无法识别的。对于简体中文,phpMyAdmin可识别gbk/utf8;繁体中文,可识别big5/utf8。如果你确定想使用这种“不正确”的字符集(事实上通常在MySQL 4.1之前大家都是用“不正确”的字符集存储数据的)存储中文论坛数据,那么请使用phpMyAdmin 2.5.x的老版本,他会使用最老和最普通的方式连接数据库,这样便可以正常管理。
0 v0 a" D* e! T7 T7 o. d3 s
我的论坛原来使用Discuz! 4.0.0 RC版本+MySQL 4.1没有问题,但升级到正式版后就有了乱码
$ H: k5 v! @% X# [浏览这问题前请您先看一下上一个问题的解答,您的情况和上面的情况差不多。RC版本使用“最老和最普通的方式”连接数据库,因此你如果使用“不正确”的字符集存储,事实上是没有问题的,但Discuz! 4.0.0正式版使用了与phpMyAdmin新版本相同的“正确”的数据库字符集,因此导致原来“不正确”的存储和“正确”的连接产生冲突,进而发生乱码。
$ i9 _( ^ ]% |
$ P$ c! S3 ]8 @解决此类问题,有如下两种方案:
3 f( t5 _1 r o$ |) {5 v$ Q2 C) C
1 v" I/ g7 J/ y% D更改存储字符集
5 w0 K( K3 t6 n$ K- D( i
主要的思想就是把数据库的字符集有latin1改为gbk,big5,或者utf8; 以下操作必须拥有主机权限。假设当前操作的数据库名为:database
, U! U# z G1 U. E0 H. g( _
( l8 h/ k" Z i1 ~导出
' i7 }1 q. e. a! O. m( @* q
首先需要把数据导为mysql4.0的格式,具体的命令如下: mysqldump -uroot -p --default-character-set=latin1 --set-charset=gbk --skip-opt databse > test.sql
( e9 {: e. O* C/ N( ^* X+ \ s0 I3 h! O0 ^9 h, S1 l, A; x0 K- S
--default-characte-set 以前数据库的字符集,这个一般情况下都是latin1的,
" S1 H+ e- a/ ~
--set-charset 导出的数据的字符集,这个可以设置为gbk,utf8,或者big5
4 n7 J# _# d1 s
导入
{- ?( ~. {7 _' N8 f" k+ S4 f首先使用下面语句新建一个GBK字符集的数据库(test)
& `, k# Q; |# M1 C( v1 |& y
% c6 s5 F" m" }* V2 b* R
CREATE DATABASE `test` DEFAULT CHARACTER SET gbk COLLATE gbk_chinese_ci;
/ c/ z& B$ U: K2 ]# a然后把刚才导出的数据导入到当前的数据库中就ok了。
: g* t' D' M1 Y% Q) W6 H5 s) s
* |/ C7 Y! C4 _4 b, M7 ?2 L
mysql -uroot -p --default-character-set=gbk -f test<test.sql
! W/ u( L7 H/ h5 j, D+ E通过以上的导出和导入就把数据库的字符集改为正确的存储方式了。
' m. E x" R, T# W
, z; C: F! m8 S1 r) @8 R3 p总结:这种方案比较麻烦,但相对以后则一直都是使用MySQL“正确”的方式进行存储和数据连接,并且新版本phpMyAdmin不会乱码。
5 X. Y/ l' H# H: ~. B
; F* ]) y: y0 v2 t
更改连接方式
, {3 Q0 r1 f. W% Y- T* I
Discuz! 4.0.0
, y \, U C) E/ I# L8 X6 {
对于Discuz! 4.0.0正式版,您可以找到./include/db_mysql.class.php,将
3 O5 H: w4 L3 r. ~) o$ k) c
! G% P* n$ d- G4 Rmysql_query("SET NAMES '".str_replace('-', '', $GLOBALS['charset'])."'");
: p7 d9 h1 I3 n. [9 }, g4 d
前面加上“//”,即将其注释掉
2 `( F+ Q% Y. u Q5 w) R! A1 i5 |5 \5 r V% F8 t: _
Discuz! 4.0.0+
. H; Z; O+ w& V% t
对于Discuz! 4.0.0以后的版本,已经支持在config.inc.php中使用单独的$dbcharset来设定数据库字符集,因此可根据您的实际情况选择留空(与$charset的设置相同),或指定为特定的数据库字符集(如latin1)
7 z: r& C8 F' J+ ?, h0 |7 V
$ N, L0 C' |7 M总结:折衷方案。数据使用“不正确”的内码存储,但显示和使用能够正常,phpMyAdmin新版本乱码,老版本可用。备份和恢复时候需要特别注意字符集问题。
8 X5 j7 Z5 j$ A" V
* X/ [, _$ w& \: `! b ^. l2 ?
应当如何升级MySQL 4.0的数据到MySQL 4.1+中
: H% d% `1 I% L$ G; j- L8 N0 T, _
如果数据文件中有中文信息,那么将MySQL 4.0的数据文件,直接拷贝到MySQL 4.1中就是不可以的,即便在my.ini中设置了default-character-set为正确的字符集。虽然貌似没有问题,但MySQL 4.1的字符集有一处非常恼人的地方,以gbk为例,原本MySQL 4.0数据中varchar,char等长度都会变为原来的一半,这样存储中文容量不变,而英文的存储容量就少了一半。这是直接拷贝数据文件带来的最大问题。
& |4 x3 F7 n. e) l
. k- ^) B+ t: d# o3 u, X+ Y
所以,升级的根本,如果想使用“正确”的字符集,还是先用mysqldump导出成文件,然后导入。
% e3 l9 d- f% d5 L4 L
$ K4 }* n1 s1 ^, L3 G至于如果原来用的latin1,现在在MySQL 4.1中还想继续“错误的”使用latin1,那么只需把default-character-set设置为latin1,并且在论坛中更改连接方式即可,这样的情况是可以直接拷贝数据文件的。
7 A0 G' [* X: D. R