Mysql 数据库字符集转换及版本升/降级教程
最近discuz发布了新的版本,免费了,用的人更多了,以前使用其它论坛程序和discuz2.5/3.0的纷纷转换或升级到discuz4.0,可见discuz作为中国人开发的php论坛程序,确实是非常优秀的,在大家欣喜若狂的时候,也遇到了一些问题
& d7 ]$ o c2 S y- i' \& Q( B+ r5 w g/ W8 k0 ~, S
看到不少用户反映转换完以后是乱码的情况,出现这种现象的主要原因是这类用户使用的都是mysql4.1以上的版本.下面作一个说明,希望出现这个问题的朋友都能耐心的把这个文档看完!!!
$ x( t. b' V: F: Z6 L! W5 M& S; j' f3 w* K Z
MySQL 4.1开始,对多语言的支持有了很大变化 (这导致了问题的出现)。尽管大部分的地方 (包括个人使用和主机提供商),MySQL 3、4.0 仍然占主导地位;但 MySQL 4.1 乃至5.0是 MySQL 官方推荐的数据库,已经有主机提供商开始提供并将会越来越多;因为 latin1 在许多地方 (下边会详细描述具体是哪些地方) 作为默认的字符集,成功的蒙蔽了许多 PHP 程序的开发者和用户,掩盖了在中文等语言环境下会出现的问题。 4 y8 }" p" U% @& E6 |( P& w& o
! o9 R$ {- h3 y+ H0 C: J9 m, c MySQL 4.1开始把多国语言字符集分的更加详细,所以导致数据库迁移,或则dz论坛升级到4.0后(dz4.0开始使用gbk或utf-8编码)出现乱码问题。
% k6 N+ |" I' q# Y' H! k
( E0 G$ H* G" b3 s: s. x& a MySQL 4.1的字符集支持(Character Set Support)有两个方面:字符集(Character set)和排序方式(Collation)。对于字符集的支持细化到四个层次: 服务器(server),数据库(database),数据表(table)和连接(connection)。
* e0 v5 B( p1 K% K1 g$ a# k# W3 E, A$ ? E9 u1 n3 Y
查看系统的字符集和排序方式的设定可以通过下面的两条命令:
& i1 y1 j4 c. U! u8 A# k( N) s1 S% E y1 ~
+ i P, T. V" ~* b; cQUOTE:
) z* p G! X- {* m% d8 amysql> SHOW VARIABLES LIKE 'character_set_%';
6 I6 u T( J( B3 ~$ M3 I -------------------------- ----------------------------
$ G" L" r3 W) n/ K2 b| Variable_name | Value |
7 d% f q* l; H; Q -------------------------- ---------------------------- 9 x }3 N+ h7 t1 j
| character_set_client | latin1 |. f4 X7 z7 G# i8 ^+ y
| character_set_connection | latin1 |
7 Z2 b+ ]( n/ c3 J$ c| character_set_database | latin1 |9 }$ ]& J6 n( B/ H
| character_set_results | latin1 |
% l% N+ a; R. W| character_set_server | latin1 |
6 i% n; @# }" f( A, d) r| character_set_system | utf8 |
, W% E h# m* o1 F( m# T| character_sets_dir | /usr/share/mysql/charsets/ |+ {( I/ I1 a; T( s, ?
-------------------------- ---------------------------- - S, [9 W, w \3 R5 B
7 rows in set (0.00 sec)9 T: ]9 l, _) h) Y1 O* j
( J% m/ Z0 D& M+ |& ]
mysql> SHOW VARIABLES LIKE 'collation_%';
, T3 t+ a$ b7 Y6 w9 w5 _+ W( J. G ---------------------- ------------------- - ~3 J$ w/ k. _# [: D D7 [) E
| Variable_name | Value |
" R: y; |4 i2 O5 {) _. j ---------------------- ------------------- - R! e: t) x% \ v# A2 H, [
| collation_connection | latin1_swedish_ci |
3 g3 m/ j4 x, X; o I5 S% f& S| collation_database | latin1_swedish_ci |- [. `3 e& K) G, l7 `
| collation_server | latin1_swedish_ci |
+ O3 A+ T; n4 O ---------------------- ------------------- % p! A( P( Q; E- i: m
3 rows in set (0.00 sec)
1 H* C; r4 N5 t! O# B5 B$ T8 O, I9 s
" @7 A" W4 [1 T1 f$ ]) Z MySQL 4.1 对于字符集的指定可以细化到一台机器上安装的 MySQL,其中的一个数据库,其中的一张表,其中的一栏,应该用什么字符集。但是,传统的 Web 程序在创建数据库和数据表时并没有使用那么复杂的配置,它们用的是默认的配置,那么,默认的配置从何而来呢?
. _( r6 x0 {! `: o+ K4 k0 Q' q5 i- f! Z) ]6 D5 s' ?9 e
编译 MySQL 时,指定了一个默认的字符集,这个字符集是 latin1;
. S/ k% \- [/ c# c. t( U, R
* t2 t3 o8 p% H- S/ n 安装 MySQL 时,可以在配置文件 (my.ini) 中指定一个默认的的字符集,如果没指定,这个值继承自编译时指定的; 3 A0 P9 {) ^& k/ N& C7 u
: S7 K( j' k4 J5 z0 Q
启动 mysqld 时,可以在命令行参数中指定一个默认的的字符集,如果没指定,这个值继承自配置文件中的; ( `! E! E& `; k5 ~7 ]- N# @% L- e
9 H' `5 y0 t' ~$ i7 \" B- T" D
此时 character_set_server 被设定为这个默认的字符集;
- z. N/ G& b2 o- W
( c( Y. v8 U; F, q% V5 x# [ 当创建一个新的数据库时,除非明确指定,这个数据库的字符集被缺省设定为 character_set_server;
- _, R3 z" }: z0 @" z" i
: H; O; Q0 D* u% J: A 当选定了一个数据库时,character_set_database 被设定为这个数据库默认的字符集;
: l/ C- Y8 X, F) ^* u% ` |) J' D4 M) K! T5 b" f4 Q
在这个数据库里创建一张表时,表默认的字符集被设定为 character_set_database,也就是这个数据库默认的字符集;
! W( @9 f: J& c1 y, T/ q, i) E I3 _; ]. L g$ W' j
当在表内设置一栏时,除非明确指定,否则此栏缺省的字符集就是表默认的字符集; ' C5 U& W8 q7 I4 b5 o
, Z$ r1 n |# `, F, W 这个字符集就是数据库中实际存储数据采用的字符集,mysqldump 出来的内容就是这个字符集下的; 9 g) l3 E! ~ U4 O: E# p
" v3 _2 f& [, |/ q1 @( G* ^
当我们按照原来的方式通过PHP存取MySQL数据库时,就算设置了表的默认字符集为utf8并且通过UTF-8编码发送查询,你会发现存入数据库的仍然是乱码。问题就出在这个connection连接层上。 & ?+ k: g& F$ P) O$ _5 G
! Z% v$ ]( M8 B) o$ S 想要进行“正确”的存储和得到“正确”的结果,最方便的是在所有query开始之前执行一下:
p0 }9 t$ v$ H8 r) f! Z" S8 n$ _* C2 ] d( E* R7 v$ H+ @' G# G d
SET NAMES 'gbk'; ! k" o: r% i) Z, c P
, S1 b G5 s1 Z
其中gbk是数据库字符集。
?$ ]4 K4 Y4 F6 B
" e% g8 r0 F8 t2 O' b+ A5 v它相当于下面的三句指令:( d0 q$ ^' E# ~+ n- }8 Z0 r
SET character_set_client = gbk;
+ g% L' ^6 o+ W6 y; dSET character_set_results = gbk;* F \) L, r! W% y/ X
SET character_set_connection = gbk;# ^; J5 G4 l3 [/ g/ x
, k: _4 ?" u! h6 d+ j; q
4.1和5.0默认使用的是latin1字符集(木头:妈的,老外真霸道,妄想让全世界都是使用瑞典字符集吗)
5 X3 C6 H0 e' Z, f& V6 _: N- _1 F如果我们只想使用gbk字符集存储和获取数据,: X0 w6 D3 t* ]7 J# z
我们在编译mysql 4.1和 5.0的时候,需要注意在my.ini或者my.cnf中添加两处参数0 Q! y/ \* d5 [8 E4 \. C
4 Y0 S+ j' ~. _' d) N" w. ]+ z" f9 A! i6 _' I; }
[Copy to clipboard] [ - ]/ u4 x5 z1 `! ~ F& a
CODE:
( f( @3 ~$ v9 d- m( o( `[mysqld], F% b9 [" P2 Z% e& U& \' B
default-character-set=utf8
9 J7 W- \' y* [6 P5 h" k" p
1 |1 w; O3 R4 R2 r2 V$ l2 @: J! o2 m" ^9 r0 X3 n2 d
' g. Z" |- b. A
& _5 `1 o) u0 Z3 G. y
[Copy to clipboard] [ - ]( W8 O) I( ], D, h
CODE:$ p" m( n# b: r4 t& L
#settings for clients (connection, results, clients)# f+ x) b3 A U) W8 p
[mysql]
% x. A4 `9 a* adefault-character-set=utf8, \$ a0 H U/ A
2 N3 b! i" m. x. v: N下面我们来说主题,如何转换数据库字符集6 e/ ]. H2 \+ p7 b( ~% j
两种方法,9 `: J9 i, W2 {/ R& h
Y$ ]7 H( Y7 v2 ]2 [8 V$ Y" {& d+ m+ C2 M, `$ d
QUOTE:
5 J8 a- @" y0 U第一种----更改存储字符集/ B+ Y0 H8 B4 E; b- k' }
主要的思想就是把数据库的字符集有latin1改为gbk,big5,或者utf8; 以下操作必须拥有主机权限。假设当前操作的数据库名为:database
1 F% @+ `, p8 T# m! L# c! h+ [& i0 h% H, O. D
导出
/ r- B: L% v A- v) g* K9 a首先需要把数据导为mysql4.0的格式,具体的命令如下:
; F( I W8 k" k( ~( zmysqldump -uroot -p --default-character-set=latin1 --set-charset=gbk --skip-opt databse > d4.sql 2 G+ @, g. ?9 E' k$ D1 r& Z& g+ Y, }- x
, E" j5 ]( Y' Q/ i* T# M( E1 _--default-characte-set 以前数据库的字符集,这个一般情况下都是latin1的,
/ \2 g( ?( ~* u2 p- U& A--set-charset 导出的数据的字符集,这个可以设置为gbk,utf8,或者big5
( A& O' z' Z1 E. t+ E3 G1 ?9 @导入. k! t1 M3 g" L& j5 s, X
首先使用下面语句新建一个GBK字符集的数据库(test) / X; s# q) J$ ?* O( v$ i
2 x6 o1 V" a3 B; j' ^) s
CREATE DATABASE `d4` DEFAULT CHARACTER SET gbk COLLATE gbk_chinese_ci;3 ~9 c" h8 w; l; ]& _0 T6 K8 i H8 ]
然后把刚才导出的数据导入到当前的数据库中就ok了。 ! @& H- [0 O9 ]4 H
- ]; C% {; x' n& c. |0 zmysql -uroot -p --default-character-set=gbk -f d4<d4.sql9 X: I" S" F7 p6 P7 t. ?
通过以上的导出和导入就把数据库的字符集改为正确的存储方式了。3 L6 ?% d2 Z; T' b: N
. L% e, E. a( Y# P" p0 a
其中d4为新建库的名称,d4.sql为导出文件的名字/ ^# A6 n' m$ ~+ M$ p7 t
9 P( u6 D: Z: ~: M Y
但是这种方法,发现数据库数据存储量无端变大30%,真是郁闷
4 I# |! I8 t! B% _! B+ m- M) s) {- K9 G8 P3 L1 [+ k( u8 ?: Y
( h9 H/ G% S, g1 I! n# z( x5 }2 d- L
2 y1 x2 }6 _2 d& l" G# e
% d7 [( E9 y' n; @8 N: i) GQUOTE:
* d+ m9 Q5 ^5 K5 g4 _( X9 z另外一种其实原理相同,但是需要手动操作,一般用于第一种方法失败后的选择! C5 @# p2 L" }# x
不过这种方法如果数据库很大,估计很难做,因为光打开文件就能让你死机
/ e+ K- i' F: i' j/ x/ v" {" r' @+ K4 i5 T$ s
首先还是用phpmyadmin或者用mysql本身的dump导出 .sql文件" Z! Y @5 |% n X! }3 s6 V- Y6 R
7 I2 ^7 z% @4 \7 e, s+ b然后用UltraEdit打开你备份的所有xxxx.sql文件,查找6 B3 m/ t% h( V" M7 ?6 O
& j2 `( O7 \/ Z6 _3 |" @% h' G9 t# R4 g+ u* H0 @/ D' n0 m
[Copy to clipboard] [ - ]
+ o) j: V+ Y; |1 j2 A+ z9 X; {CODE:* O6 @ O7 n" A3 x4 v
DEFAULT CHARSET=latin1 0 r2 ?/ d/ _: [( H7 ~7 B% d# e) }% k/ A
. l1 w( o! I6 E9 g2 r; B% i6 tlatin1这里也许是别的,反正是你不想要的,要转成gbk或者big5的字符集
) j1 T' o" N0 e& Q把这个替换为“空”3 o# z: q* C/ d% U2 B' u. C
在查找" Q1 d" a8 X& M- R1 S
/ t7 ^# K7 ]+ r
5 g7 ^7 p5 O5 S[Copy to clipboard] [ - ]
x8 P; i- t7 i3 VCODE:
1 ?; ^1 x1 Y3 v# R. q0 D# J- O3 HCREATE TABLE cdb_sessions (# I- P% a) r; y( f! h, k: B( W
sid char(6) character set latin1 collate latin1_bin NOT NULL default '',
" M& m" F" ^$ z' b3 Uip1 tinyint(3) unsigned NOT NULL default '0',4 A3 n2 D' d/ Y5 Z; C& `
ip2 tinyint(3) unsigned NOT NULL default '0',
! s' B8 ?+ q( U2 kip3 tinyint(3) unsigned NOT NULL default '0',, W( g8 H1 Z; I& O
ip4 tinyint(3) unsigned NOT NULL default '0',
, {" M) |( w' M8 Ouid mediumint(8) unsigned NOT NULL default '0',. o. b' {7 M# }) |" O. P, a
username char(15) NOT NULL default '',7 D, \. g' y& s7 n
groupid smallint(6) unsigned NOT NULL default '0',4 Q1 ]& k. v9 b" v- h9 _: \9 X, A
styleid smallint(6) unsigned NOT NULL default '0',+ d3 q. w, F: y3 ^5 m' L
invisible tinyint(1) NOT NULL default '0',
$ W4 t8 v/ }! h4 j`action` tinyint(1) unsigned NOT NULL default '0',; B5 ]% C8 f2 c- D
lastactivity int(10) unsigned NOT NULL default '0',+ A: o& ?( n! A/ o( }' U6 w
fid smallint(6) unsigned NOT NULL default '0',
# ?+ Y1 P' W" Q. Ptid mediumint(8) unsigned NOT NULL default '0',$ n' x* v7 f5 D) |
nickname char(15) NOT NULL default '',
4 `5 Z1 ]9 c6 \6 DUNIQUE KEY sid (sid)9 O: U- A) X; f6 v* H; D( _
) ENGINE=HEAP MAX_ROWS=1000;5 t7 U9 p8 ^, L
# k* u& W) T/ y
替换为
/ \7 N7 f& n$ ]1 I+ S8 H& J8 r
X z9 i8 r3 d. l( \! ?* `# k
. k0 I& d% [/ l6 w" e2 s6 ^[Copy to clipboard] [ - ]
4 m% i, a/ W) R; k- I! P5 H. UCODE:
2 L0 N' q% E& G/ V$ uCREATE TABLE `cdb_sessions` (
8 A2 r8 l8 R% V7 C5 H1 b5 [$ p/ S# a`sid` char(6) binary NOT NULL default '',
8 `: ~- J8 \6 s9 I2 E8 T# {1 d2 y5 p8 S6 G`ip1` tinyint(3) unsigned NOT NULL default '0', i% W/ \! i- p/ E
`ip2` tinyint(3) unsigned NOT NULL default '0',
7 ?% N# o# o' s0 D! j`ip3` tinyint(3) unsigned NOT NULL default '0',
+ ?5 ^9 ^/ ^" r3 x`ip4` tinyint(3) unsigned NOT NULL default '0',( |" a F2 T. D0 `' x3 J/ z, `
`uid` mediumint(8) unsigned NOT NULL default '0',6 u* q1 d! r0 j5 z2 J
`username` char(15) NOT NULL default '',
( e! A0 m& L" \8 y`groupid` smallint(6) unsigned NOT NULL default '0',
. T! Y6 ?4 M6 x# G6 N" Z- C`styleid` smallint(6) unsigned NOT NULL default '0',
; C9 c. g) U$ l`invisible` tinyint(1) NOT NULL default '0',
; j( m( _$ k" Y9 Y) g8 f, N1 p`action` tinyint(1) unsigned NOT NULL default '0',* I3 t* j8 Z! J, X* a% a+ @" p, z
`lastactivity` int(10) unsigned NOT NULL default '0',: j" A |* ~8 H( y* P
`fid` smallint(6) unsigned NOT NULL default '0',' O$ d& e( A2 C. |. R
`tid` mediumint(8) unsigned NOT NULL default '0',
, v8 H7 h) y4 B& [8 P! v/ x`nickname` char(15) NOT NULL default '',' S$ @! r2 r M, x, s
UNIQUE KEY `sid` (`sid`)
. H' `1 F- p, E) N9 c8 c) TYPE=HEAP MAX_ROWS=2000;# c7 Z4 i. F8 `" M
! g- g. n( ?1 C" P6 g( _; x 这一步更为简单的办法就是删除掉关于cdb_sessions表的这一段,将来全新装一个d4,将这个表导出2 R; {* s( Z5 I" C& R
将其内容复制,粘贴到 sql文件的最后面& G' K0 A& n5 i/ c
: l9 {' s# q7 k: g5 q- n, n
保存后,再把这个sql文件导入到你的库中
% W- f: m v% q8 b/ \; {, M. J; n. F! M$ v& d, ?* X
就OK了
1 U% t2 l0 _, Q5 r. `' h) ?8 W4 u2 a/ L" W! r9 k
用这两种方法就可以很方便的把4.1和5.0的mysql数据库降级到4.06 F, D% [6 `9 U+ G& t+ o5 T: E( n7 `, Q
简单的过程就是+ ]9 f0 j( j4 [) {
A导出4.1/5.0的库
3 y) B# c7 ^% i( b) ~B进行处理,转换成gbk字符集( _0 A4 W6 W1 B1 G6 M% z. W' c
C彻底卸载4.1或者5.0
$ N" {3 u( D. s4 V& i; s8 nD安装4.0.26% K# F! s- F) w+ P. e; B. \% K
E然后导入处理完的库
m: R X- R1 O+ @& H/ w' F& p: G. g$ M W% s0 x
降级的时候导出库可以用这个方法& c; n" F7 g3 S6 @$ s
mysqldump -uroot -p --default-character-set=latin1 --set-charset=gbk --skip-opt databse --compatible=mysql40 > d4.sql
# {% H S( M, s) p* r这样导出的就是4.0的库勒
$ N4 A. D$ x( ]% L+ d P$ ]7 F K2 c( N2 c: G
至于mysql版本的升级,
1 J3 t1 b- P+ a 如果数据文件中有中文信息,那么将MySQL 4.0的数据文件,直接拷贝到MySQL 4.1中就是不可以的,即便在my.ini中设置了default-character-set为正确的字符集。虽然貌似没有问题,但MySQL 4.1的字符集有一处非常恼人的地方,以gbk为例,原本MySQL 4.0数据中varchar,char等长度都会变为原来的一半,这样存储中文容量不变,而英文的存储容量就少了一半。这是直接拷贝数据文件带来的最大问题。
7 F4 b; J, U0 A, J$ e4 G
; |5 d+ g% o1 ] 所以,升级的根本,如果想使用“正确”的字符集,还是先用mysqldump导出成文件,然后导入。
点击图标进入精品网摘收藏 欢迎大家加入网络收藏夹