个人建议,数据库字符集尽量使用utf8(utf-8),以使你的数据能很顺利的实现迁移,因为utf8字符集是目前最适合于实现多种不同字符集之间的转换的字符集,尽管你在命令行工具上无法正确查看数据库中的内容,我依然强烈建议使用utf8作为默认字符集. 接下来是完整的一个例子: 1.创建数据库表 mysql>CREATE DATABASE IF NOT EXISTS my_db default charset utf8 COLLATE utf8_general_ci; #注意后面这句话 "COLLATE utf8_general_ci",大致意思是在排序时根据utf8变码格式来排序 #那么在这个数据库下创建的所有数据表的默认字符集都会是utf8了 mysql>create table my_table (name varchar(20) not null default '')type=myisam default charset utf8; #这句话就是创建一个表了,制定默认字符集为utf8 2.写数据 例子1是通过php直接插入数据: a.php <?php mysql_connect('localhost','user','password'); mysql_select_db('my_db'); //请注意,这步很关键,如果没有这步,所有的数据读写都会不正确的 //它的作用是设置本次数据库联接过程中,数据传输的默认字符集 mysql_query("set names utf8;"); //必须将gb2312(本地编码)转换成utf-8,也可以使用iconv()函数 mysql_query(mb_convet_encoding("insert into my_table values('测试');", "utf-8", "gb2312")); ?> 例子是通过页面提交插入数据2: b.php <?php //输出本页编码为utf-8 header("content-type:text/html; charset=utf-8"); mysql_connect('localhost','user','password'); mysql_select_db('my_db'); if(isset($_REQUEST['name')) { //由于上面已经指定本页字符集为utf-8了,因此无需转换编码 mysql_query(sprintf("insert into my_table values('%s');", $_REQUEST['name'])); } $q = mysql_query("select * from my_table"); while($r = mysql_fetch_row($q)) { print_r($r); } ?> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <form action="" method="post"> <input type="text" name="name" value=""> <input type="submit" value='submit'> </form> 自此,使用utf8字符集的完整的例子结束了. 如果你想使用gb2312编码,那么建议你使用latin1作为数据表的默认 字符集,这样就能直接用中文在命令行工具中插入数据,并且可以直接 显示出来.而不要使用gb2312或者gbk等字符集,如果担心查询排序等 问题,可以使用binary属性约束,例如: create table my_table ( name varchar(20) binary not null default '')type=myisam default charset latin1; 附:旧数据升级办法 以原来的字符集为latin1为例,升级成为utf8的字符集。原来的表: old_table (default charset=latin1),新表:new_table(default charset=utf8)。 第一步:导出旧数据 mysqldump --default-character-set=latin1 -hlocalhost -uroot -B my_db --tables old_table > old.sql 第二步:转换编码 iconv -t utf-8 -f gb2312 -c ol在这里,假定原来的数据默认是gb2312编码。 第三步:导入 修改old.sql,增加一条sql语句: "SET NAMES utf8;",保存。 mysql -hlocalhost -uroot my_db < new.sql 大功告成~~ =============================== Mysql自4.1以后,增加了对字符集的支持。笔者之前对Mysql比较了解,刚接触4.1时,感觉Mysql有点多此一举,但后来细想发现,对字符集的支持,虽然对开发者来说,会麻烦一些,但不可否认,是一种进步。对字符集的支持,不仅更加支持多语言,而且,也方便移植。 刚开始使用Mysql4.1,你可能感觉有点不适,下面,简单阐述一下笔者对Mysql4.1字符集的理解,再讲述如何PHP如何适应Mysql的这种变化,希望大家看过这文章后,能够有所收获。 如果你对计算机基础知识不了解,请直接阅读“结论篇” 一(原理篇 Mysql的字符集里有两个概念,一个是“Character set(字符集)”,另一个是“Collations”。 1. Collations Collations翻成中文是“校验”,在网页开发的过程中,这个词汇,只在Mysql里使用,主要作用是指导Mysql对字符的比较,比如, ASCII字符集里,Collations规定了a小于b,a等于a,以及a是否等于A之类的。通常,大家基本可以忽略Collations的存在,因为每个字符集都有一个默认的Collations,通常,使用默认的Collations就可以了。 2.字符集 与这对比的是,字符集是个更广的概念,即使是Windows下普通的文本文件,也渗及到字符集的问题。不同的字符集,规定了不同的字符的编码方式。一个 character set (字符集)是一组符号和编码,比如, ASCII字符集,包括的字符有:数字,大小写字母,分号、换行之类的符号,编码方式是用一个7bit表示一个字符(A的编码是65,b的编码是98)。ASCII只规定了英文字母的编码,非英文语言不能用ASCII编码表示,为此,不同的国家,都为自己的语言做了编码,比如,我们国家,就有GB2312编码。但每个国家之间的编码不同,也存在着一些跨平台的问题,为此,一些国际化标准组织,就制定了一些国际通用的编码,最常用的就是UTF8了。ASCII只对英文符号和英文字母做了编码,GB2312对英文符号,英文字母,汉字做了编码,UTF8对世界上所有的语言文字做了编码,所以,GB1212的字符包含ASCII字符,UTF8包含了GB2312字符。由此可见,UTF8是所含最广字符的字符集,所以,在一些多语言的WEB系统中,一般用UTF8字符集(PHPMyAdmin使用UTF8编码)。 任何文本的存储,都渗及到字符集的概念。包括数据库,也包括普通的文本文件。 主要术语: 字符:汉字,英文字母,标点符号,拉丁文等等。 编码:将字符转换成计算机存储的格式,比如,A用65表示字符集:一组字符以及对应的编码方式。 a. Mysql的字符集 Mysql目前支持多字符集,并且,支持在不同的字符集之间转换(便于移植和支持多语言)。 Mysql可以设置服务器级字符集、数据库级字符集、数据表级字符集、 表列的字符集,实际上,最终使用字符集的地方是存储字符的列,比如,你设置 table1中col1列是字符类型,col1才用到了字符集,如果table1表的col2列是int类型,col2不使用字符集的概念。 服务器级字符集、数据库级字符集、数据表级字符集都是为列的字符集做默认选项的。 Mysql一定有一个字符集,可以通过启动时加参数指定,也可以编译时指定,也可以在配置文件里指定。Mysql服务器字符集,只是做为数据库级的默认值。创建数据库时,你可以指定字符集,如果没指定,就使用服务器的字符集。同理,创建表时,你可以指定表级的字符集,如果没指定,使用数据库的字符集做为表的字符集。创建列时,你可以指定某列的字符集,如果没指定,就使用表的字符集。 通常情况下,您只需设置服务器级的字符集,其它的数据库级,表级,以及列级的字符集,都继承自服务器级字符集。 由于UTF8是最广的字符集,所以,一般情况下,我们设置Mysql服务器级的字符集为UTF8~ b. 普通文本的字符集问题 任何文本的存储,都存在着字符集的问题,普通文本文件也不例外。 Windows2000+的系统中,打开记事本,“保存为„”对话框,就有一个选项,可以让你选择存储文本的编码方式。 通常情况下,大家都使用Windows2000+的系统,都使用默认的编码,所以,不会碰到字符集的问题。 Windows下,保存文本文件时,可以选择编码方式,但打开文本文件 时,都是自动判断编码方式的。网上有一个用Windows2000+的记事本玩移动,联通的笑话,大家可以搜搜,就是因为Windows在打开文本文件时,编码判断错误引起的问题。 因为自动判断编码有时会错误,所以,有的文本文件,规定了如何识别自身所使用的编码。HTML文件就是一个这样的例子。 HTML是文本文件。存储HTML文件的时候,需要使用一个编码,并且,在HTML文件里,也使用HTML语法,指定了该文件所使用的编码(比如)。如果HTML文件没有指定编码,则浏览器自动识别文件的编码。如果HTML指定了编码,则浏览器使用HTML指定的编码。 通常情况下,HTML文件指定的charset和HTML文件自身的编码是一致的,但也有不一致的情况,如果不一致,就会导致网页乱码(此处乱码,只和文本文件有关,和数据库无关。)使用专门的网页编辑工具(比如Dreamwave),会自动根据网页中的charset值来编码文件。 c. php+mysql的字PHP最终生成的是文本文件,但他要取数据库里的文本,或将文本存进数据库。 由于Mysql支持多字符集,默认情况下,Mysql不知道PHP发给他的是什么编码的字符,所以,Mysql要求客户端(PHP)告诉他存取的字符集是什么。 PHP通过设置character_set_client,告诉Mysql,PHP存进数据库的是什么编码方式。 PHP通过设置character_set_results,告诉Mysql,PHP需要取什么样 编码的数据。 PHP通过设置character_set_connection,告诉Mysql,PHP查询中的文本,使用什么编码。 MYSQL使用设置的编码方式存储文本。 假设Mysql使用setserver来存储文本,PHP的character_set_client是setclient,PHP的 character_set_results是setresult。那么,Mysql将PHP发来的文本,从setclient编码方式,转换成 setserver编码方式,再存入数据库,如果PHP取文本,Mysql将文本从setserver转换成setresult,再发送给PHP。 PHP文件(最终生成的HTML文件)本身有个编码,如果Mysql传过来的编码,与PHP文件自身的编码不同,那么,整个网页,必然乱码。所以,PHP一般将自己的编码方式,告诉Mysql。 要保证不乱码,就必须将三个编码统一:一是网页自身的编码,二是HTML里指定的编码,三是PHP告诉Mysql的编码(包括character_set_client和character_set_results)。 第一和第二个编码,如果使用DW之类的编辑器写的网页,通常是一致的,但用记事本写的网页,有可能不一致。 第三个编码,需要手工通知Mysql。这步可以通过在PHP里使用mysql_query(“set names characterX”)来实现。 d.字符集的转换问题 如果小字集转换成大字符集,不会丢失数据,但大字集,转换成小字集,可能会丢失数据。 比如,UTF8里有的字符,GB2312不一定有,所以,从UTF8转换到GB2312可能会丢失一些字符。 但有种情况例外,先从GB2312转成UTF8,再从UTF8转成GB2312,这种情况是不会丢数据的,因为,刚开始转换的文本,都是GB2312里的字符,所以,整个过程都是GB2312的字符在转换,不会丢失。 正因为UTF8能容纳世界上的所有字符,所以,数据库一般使用UTF8编码。这使得,任何字符都可以存进UTF8编码的数据库。 e. PHPMyAdmin乱码的问题 PHPMyAdmin支持多国语言,这就必定要求HTML页面使用UTF8编码。 HTML页面使用UTF8编码,这就必定要求PHPMyAdmin连接Mysql时,character_set_client和character_set_results使用UTF8编码。 当前情况下,PHP连接Mysql只能是使用set names(或其它几个语句)来通知Mysql的编码方式,如果没有显式的声明编码方式,都将使用latin1编码。一般的程序,都没有显式声明 character_set_client变量,所以,都是将gb2312文本,按latin1编码方式存在数据库,PHPMyAdmin再用utf8格式读取,肯定是乱码的。 如果PHP程二(总结篇 上面的讲得有点乱,总结一下: 1.数据库尽量使用utf8存储(修改/etc/my.cnf,在[mysqld]段加上default-character-set=utf8) (已有的数据库,先转成UTF8格式) 2.PHP程序在查询数据库之前,执行mysql_query(“set names xxxx”);其中xxxx是你网页的编码(charset=xxxx),如果网页中charset=utf8,则xxxx=utf8,如果网页中 charset=gb2312,则xxxx=gb2312,如果网页中的charset=ipaddr,则xxxx=ipaddr (开个玩笑,没这编码) 几乎所有WEB程序,都有一段连接数据库的公共代码,放在一个文件里,在这文件里,加入mysql_query(“set names”)就可以了。 3.PHPMyAdmin不需要做改动。 4.需要注意的是,为保证网页实际编码(Windows保存对话框里的编码)和他声明的编码(charset=?)是一致的,请用DW之类的工具做网页。 写得有点仓促,希望大家指正和补充。 ======================================== 第一篇:A MySQL 4.1 Story 下面要写的是一篇非常无聊的东西,充斥了大量各式各样的编码、转换、客户端、服务器端、连接„„呃,我自己都不愿意去看它,但想一想,写下来还是有点意义的,原因有四: MySQL 4.1 对多语言的支持有了很大变化 (这导致了问题的出现); 尽管大部分的地方 (包括个人使用和主机提供商),MySQL 3 仍然占主导地位;但 MySQL 4.1 是 MySQL 官方推荐的数据库,已经有主 机提供商开始提供并将会越来越多; 许多 PHP 程序以 MySQL 作为默认的数据库管理软件,但它们一般不区分 MySQL 4.1 与 4.1 以下版本的区别,笼统地称“MySQL 3.xx.xx 以上版本”就满足安装需求了; 因为 latin1 在许多地方 (下边会详细描述具体是哪些地方) 作为默认的字符集,成功的蒙蔽了许多 PHP 程序的开发者和用户,掩盖了在中文等语言环境下会出现的问题; 简单的说,MySQL 自身的变化和使用 MySQL 的 PHP 程序对此忽略,导致了问题的出现和复杂化,而由于大部分用户使用的是英文,使这种问题不被重视。这里提到的 PHP 程序,主要就 WordPress 而言。 MySQL 4.1 字符集支持的原理MySQL 4.1 对于字符集的指定可以细化到一台机器上安装的 MySQL,其中的一个数据库,其中的一张表,其中的一栏,应该用什么字符集。但是,传统的 Web 程序在创建数据库和数据表时并没有使用那么复杂的配置,它们用的是默认的配置,那么,默认的配置从何而来呢, 编译 MySQL 时,指定了一个默认的字符集,这个字符集是 latin1; 安装 MySQL 时,可以在配置文件 (my.ini) 中指定一个默认的的字符集,如启动 mysqld 时,可以在命令行参数中指定一个默认的的字符集,如果没指定,这个值继承自配置文件中的; 此时 character_set_server 被设定为这个默认的字符集; 当创建一个新的数据库时,除非明确指定,这个数据库的字符集被缺省设定为 character_set_server; 当选定了一个数据库时,character_set_database 被设定为这个数据库默认的字符集; 在这个数据库里创建一张表时,表默认的字符集被设定为 character_set_database,也就是这个数据库默认的字符集; 当在表内设置一栏时,除非明确指定,否则此栏缺省的字符集就是表默认的字符集; 这个字符集就是数据库中实际存储数据采用的字符集,mysqldump 出来的内容就是这个字符集下的; 简单的总结一下,如果什么地方都不修改,那么所有的数据库的所有表的所有栏位的都用 latin1 存储,不过我们如果安装 MySQL,一般都会选择多语言支持,也就是说,安装程序会自动在配置文件中把 default_character_set 设置为 UTF-8,这保证了缺省情况下,所有的数据库的所有表的所有栏位的都用 UTF-8 存储。 当一个 PHP 程序与 MySQL 建立连接后,这个程序发送给 MySQL 的数据采用的是什么字符集,MySQL 无从得知 (它最多只能猜测),所以 MySQL 4.1 要求客户端必须指定这个字符集,也就是 character_set_client,MySQL 的怪异之处在于,得到的这个字符集并不立即转换为存储在数据库中的那个字符集,而是先转换为 character_set_connection 变量指定的一个字符集;这个 connection 层究竟有什么用我不大明白,但转换为 character_set_connection 的这个字符集之后,还要转换为数据库默认的字符集,也就是说要经过两次转换;当这个数据被输出时,又要由数据库默认的字符集转换为 character_set_results 指定的字符集。 一个典型的环境典型的环境以我自己的电脑上安装的 MySQL 4.1 为例,我自己的电脑上安装着 Apache 2,PHP 5 和 WordPress 1.5.1.3,MySQL 配置文件中指定了 default_character_set 为 utf8。于是问题出现了: WordPress 按照默认情况安装,所以所有的表都用 UTF-8 存储数据; WordPress 默认采用的浏览字符集是 UTF-8 (Options->Reading 中设置),因此所有 WP 页面的 meta 中会说明 charset 是 utf-8; 所以浏览器会以 utf-8 方式显示所有的 WP 页面;这样一来 Write 的所有 Post,和 Comment 都会以 UTF-8 格式从浏览器发送给 Apache,再由 Apache 交给 PHP; 所以 WP 从所有的表单中得到的数据都是 utf-8 编码的;WP 不加转换的直接把这些数据发送给 MySQL; MySQL 默认设置的 character_set_client 和 character_set_connection 都是 latin1,此时怪异的事情最神奇的还不是这个,如果 WordPress 中设置以 GB2312 格式阅读,那么 WP 发送给 MySQL 的 GB2312 编码的数据,被“当作 latin1”转换后,存进数据库的是一种奇怪的格式 (真的是奇怪的格式,mysqldump 出来就能发现,无论当作 utf-8 还是当作 gb2312 来读都是乱码),但如果这种格式以 latin1 输出出来,居然又能变回 GB2312~ 这会导致什么现象呢,WP 如果使用 MySQL 4.1 数据库,把编码改用 GB2312 就正常了,可惜,这种正常只是貌似正常。 如何解决问题如果你已经不耐烦了 (几乎是肯定的),google 一下,会发现绝大部分的解答是,query 之前先执行一下:SET NAMES 'utf8',没错,这是解决方案,但本文的目的是说明,这为什么是解决方案。 要保证结果正确,必须保证数据表采用的格式是正确的,也就是说,至少能够存放所有的汉字,那么我们只有两种选择,gbk 或者 utf-8,下面讨论 utf-8 的情况。 因为配置文件设置的 default_character_set 是 utf8,数据表默认采用的就是 utf-8 建立的。这也应该是所有采用 MySQL 4.1 的主机提供商应该采用的配置。所以我们要保证的只是客户端与 MySQL 交互之间指定编码的正确。 这只有两种可能,客户端以 gb2312 格式发送数据,或者以 utf-8 格式发送数据。 如果以 gb2312 格式发送: SET character_set_client='gb2312' SET character_set_connection='utf8' 或者 SET character_set_connection='gb2312' 都是可以的,都能够保证数据在编码转换中不出现丢失,也就是保证存储入数据库的是正确的内容。 怎么保证取出的是正确的内容呢,考虑到绝大部分客户端 (包括 WP),发送数据的编码也就是它所希望收到数据的编码,所以: SET character_set_results='gb2312' 可以保证取出给浏览器显示的格式就是 gb2312。 如果是第二种情况,客户端以 utf-8 格式发送 (WP 的默认情况),可以采用下述配置: SET character_set_client='utf8' SET character_set_connection='utf8' SET character_set_results='utf8' 这个配置就等价于 SET NAMES 'utf8'。 WP 应该作什么修改还是那句话,客户端要发给数据库什么编码的数据,数据库是不可能确切知道的,只能让客户端自己说明白,所以,WP 是必须发送正确的 SET... 给 MySQL 的。怎么发送最合适呢,台湾的 pLog 同仁给出了一些建议: 首先,测试服务器是否 >= 4.1,编译时是否加入了 UTF-8 支持;是则继续 然后测SET NAMES $dbEncoding 对于第二点,WP 的情况是不同的,按照上面的典型配置,只要用 WP,肯定数据库是用 UTF-8 存储的,所以要根据用户设置的以 GB2312 还是 UTF-8 浏览来判断 (bloginfo('charset')),但这个值是要连接数据库以后才能得到的,所以效率最高的方式是连接数据库之后,根据这个配置设置一次 SET NAMES,而不必每次查询之前都设置一遍。 我的修改方式是这样的,在 wp_includes/wp-db.php 中增加: function set_charset($charset) { // check mysql version first. $serverVersion = mysql_get_server_info($this->dbh); $version = explode('.', $serverVersion); if ($version[0] < 4) return; // check if utf8 support was compiled in $result = mysql_query("SHOW CHARACTER SET like 'utf8'", $this->dbh); if (mysql_num_rows($result) < = 0) return; if ($charset == 'utf-8' || $charset == 'UTF-8') $charset = 'utf8'; @mysql_query("SET NAMES '$charset'", $this->dbh); } 在 wp-settings.php 的 require (ABSPATH . WPINC . '/vars.php'); 后增 加: $wpdb->set_charset(get_bloginfo('charset')); ================================================ 1. MySQL 4.1 在文字上有很大改进,它有了 Character Set 与 Collation 的慨念。 2. 在 MySQL 4.0 ,一般的程式都会将文字以拉丁文 ( latin) 来储存,就算我们输入中文字,结果仍是放在以拉丁文设置的文字栏里头,这对 MySQL 4.0 与以 MySQL 4.0 为基楚的程式来说,并不会有问题。 3. 可是 MySQL 4.1 的系统编码是预设用 UTF-8 的,当要 restore MySQL 4.0 的 backup 档到 MySQL 4.1 时,乱码就出现了。原因在于 MySQL 4.1 将 latin 码转换过来,而后转换是并不完全完美的,这导致了出现少量文字出现乱码现象。 4. 要解决这乱码问题并不难。首先,在 MySQL 4.0 备份时,先将所有文字栏变成 binary 类型,然后进行正常备份。第二步,可在 MySQL 4.1 里将刚才的备份 restore。最后,将较早前所变更到 binay 类型的文字栏,再次复原到文字类型。这样中文编码的问题就应该可以完全解决。 5. 将文字栏变更到 binay 类型时,必需设定 binary 栏的长度大过或等于 (>=) 文字栏的长度,否则资料会失去。 6. 另外,经这样升级的 MySQL 数据库,在 MySQL 4.1 里将会正常工作,就算是怎样 backup 与 restore 都不会再有乱码问题。 作者: MySQL 发布日期: 2005-12-14 mysql4.1是比较烦人,支持多语言的细化设置,再加上phpmyadmin2.6也比较笨,默认就是改不动的utf8,怎么弄都乱码。 好了,废话少说,我们来一步步解决这个问题: 1.修改/etc/my.cnf文件,改成这样: [mysqld] datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock default-character-set=utf8 [mysql.server] user=mysql basedir=/var/lib [mysqld_safe] epid-file=/var/run/mysqld/mysqld.pid 注意:就是加入了一句default-character-set=utf8。 2./etc/init.d/mysqld restart 重新启动mysql; 3.打开phpmyadmin,选择lang为"Chines simplifies(zh-utf-8)",选择"MySQL 连接校对"为"utf8_general_ci "点“显示 MySQL 的运行信息”--“变量”,可以看到: character set client utf8 utf8 character set connection utf8 utf8 character set database utf8 utf8 character set results utf8 utf8 character set server utf8 utf8 character set system utf8 utf8 collation connection utf8_general_ci utf8_general_ci collation database utf8_general_ci utf8_general_ci collation server utf8_general_ci utf8_general_ci 从这里可以看到character全部变成utf8了。 有人要问,为什么都要改成utf8呢,改成GB2312不行吗, 解释如下: 我也不想改成utf8,只是phpmyadmin2.6在mysql4.1的时候只会用utf8,连其他页面的charset也都是utf8,改成gb2312一定会乱码,我们只能凑phpmyadmin了。 只有在mysql3.23的时候,phpmyadmin才会多一个gb2312的页面 charset,这时候是正常的。 3.将以前的mysql3的库文件导入mysql4.1的库 有两种情况: 一是从phpmyadmin上导入,这时候你要注意的是在选择库文件的页面左下脚有个“文件的字符集:”,默认是utf8,要改成gb2312,否则导进去乱码; 二是在linux下导入,这时候你需要先在库文件的头部加一行: SET NAMES 'gb2312'; 注意最后也是;号,别漏了。 然后执行mysql -u用户名 -p密码 xxx.sql > 库名 导入完成以后再用phpmyadmin打开看,里面的中文字就是正确的。 4.从mysql4.1里导出库文件 一.用phpmyadmin导出 导出倒是问题不大,如果phpmyadmin的浏览页面里显示的中文是正常的,那么导出肯定也是正常的 二.在linux上导出 如果用mysqldump导出出现了乱码也没有关系,可以运行iconv来转换一下 iconv -c -f UTF-8 -t GB2312 库文件名 > 新的gb2312的库文件名 综上所述,你要注意: 1。尽量在需要导入的库文件的开头加入SET NAMES 'gb2312';告诉mysql你要导入的是一个gb2312的文件; 2。可能你需要这个: SET NAMES 'utf8'; 在登陆到mysql后用,把character的一些默认参数改到utf8上,有时可以减少一些困扰,不过也不是必须的。 在mysql上使用: SHOW VARIABLES LIKE 'character_set_%'; 用来查看当前的状态。 3.如果出现乱码也不要怕,一是你要注意留存原有的备份,二是用iconv来进行转化。 在正常使用之前注意做导入导出的测试,确保万无一失。 最后加一句:www.quicklinux.org原创文章,转载请注明出处。呵呵 邮件:support@quicklinux.org 作者: MySQL 发布日期: 2005-12-14 我升级了MYSQL到4.1.2,phpmyadmin用的是2.6.2。数据表里面有中文的字段中文都变成了乱码,导出数据也是乱码。我用 和字符相关的变量中这几个和sql很有关系: character_set_client character_set_connection character_set_results 此外就是数据库中对相应字段设置的charact set,如果没有对字段设置,缺省是table的charact set,table也没有指定则缺省使用database 的。 上面3个变量的作用是这样的,client表示客户端发送过来的字符集,results表示发送到客户端的字符集(这两个分开是因为发送过来和发送过去的不一定是同一个客户端),connection则在客户端和数据库起一个连接作用。 具体是这样:比如我在mysql命令行设置client为gbk,connection为utf8,results为gbk,数据库为big5, 当我发送一个insert语句的时候,这个语句作为gbk代码,先转为utf8代码(connection),再转为big5(database)插入数据库。 而运行一个select语句的时候,从数据库得到的结果则相反的过程,由big5转为utf8,再转为gbk,你得到gbk的结果。 因此最主要的是让client和results和你使用的客户端一致。比如你的网页是utf8编码,你就要设置这两个为utf8。 而在mysql命令行的时候,我用的是2000,需要设置为gbk 而我们用的set names XXX,实际上就是同时设置这3个变量为XXX。 在这样的情况下,我们可以把一个数据库中的不同表或不同字段设为不同的字符集,只要上面3个设置正确,就可以在数据库中同时使用不同的字符集。 注意要保证你的数据库中的字符已经使用了正确的字符集,比如如果一开始你设置错误,插入数据后,本身数据的编码就是不正确的,然后即使设置改回来,也不可能得到正确的显示了。 还有一个是编码互相之间的兼容性,如果一个字符在gbk中有,在 utf8中没有,那么在gbk,》utf8,》gbk的过程中,它就变成了“,” 再说一下具体解决的办法。 首先要指定你的升级后的database及table及field的character set,一般来说我们用gb2312或者utf8的,如果不同时使用多种编码,只要指定database就可以,可以在建库的sql语句加上相应的character set,在phpMyAdmin里也可以修改。 然后是导入旧数据。首先要确定自己的数据文件的编码。如果用phpMyAdmin导入,在界面上有文件编码的选项,一定要和数据文件的编码一致。 如果从mysql的命令行导入,就要自己设置上面说到的3个变量,set names xxx。 使用其它的客户端程序一样要注意。 这样就可以让旧数据转入新数据库后的编码才是正确的,如果这一步错了,后面不可能得到正确的显示。 然后是自己的程序,在连接后就可以执行一次set names xxx,根据你的网页编码而定。 这样基你很有可能是导入的数据编码已经不对了。 作者: MySQL 发布日期: 2005-12-14 以上文章基本概括了MySQL4.1的编码问题。 如果有足够的时间,大家可以研究本论坛上的一些编码转换的代码,编程自己实现。 作者: safer 发布日期: 2005-12-15 ============================== 看到不少用户反映转换完以后是乱码的情况,出现这种现象的主要原因是这类用户使用的都是mysql4.1以上的版本.下面作一个说明,希望出现这个问题的朋友都能耐心的把这个文档看完!!! MySQL 4.1开始,对多语言的支持有了很大变化 (这导致了问题的出现)。尽管大部分的地方 (包括个人使用和主机提供商),MySQL 3、4.0 仍然占主导地位;但 MySQL 4.1 乃至5.0是 MySQL 官方推荐的数据库,已经有主机提供商开始提供并将会越来越多;因为 latin1 在许多地方 (下边会详细描述具体是哪些地方) 作为默认的字符集,成功的蒙蔽了许多 PHP 程序的开发者和用户,掩盖了在中文等语言环境下会出现的问题。 MySQL 4.1开始把多国语言字符集分的更加详细,所以导致数据库迁移,或则dz论坛升级到4.0后(dz4.0开始使用gbk或utf-8编码)出现乱码问题。 MySQL 4.1的字符集支持(Character Set Support)有两个方面:字符集 (Character set)和排序方式(Collation)。对于字符集的支持细化到四个 层次: 服务器(server),数据库(database),数据表(table)和连接 (connection)。 查看系统的字符集和排序方式的设定可以通过下面的两条命令: 引用内容: mysql> SHOW VARIABLES LIKE 'character_set_%'; +--------------------------+----------------------------+ | Variable_name | Value | +--------------------------+----------------------------+ | character_set_client | latin1 | | character_set_connection | latin1 | | character_set_database | latin1 | | character_set_results | latin1 | | character_set_server | latin1 | | character_set_system | utf8 | | character_sets_dir | /usr/share/mysql/charsets/ | +--------------------------+----------------------------+ 7 rows in set (0.00 sec) mysql> SHOW VARIABLES LIKE 'collation_%'; +----------------------+-------------------+ | Variable_name | Value | +----------------------+-------------------+ | collation_connection | latin1_swedish_ci | | collation_database | latin1_swedish_ci | | collation_server | latin1_swedish_ci | +----------------------+-------------------+ 3 rows in set (0.00 sec) MySQL 4.1 对于字符集的指定可以细化到一台机器上安装的 MySQL,其中的一个数据库,其中的一张表,其中的一栏,应该用 什么字符集。但是,传统的 Web 程序在创建数据库和数据表时并没 有使用那么复杂的配置,它们用的是默认的配置,那么,默认的配置 从何而来呢, 安装 MySQL 时,可以在配置文件 (my.ini) 中指定一个默认的的字符集,如果没指定,这个值继承自编译时指定的; 启动 mysqld 时,可以在命令行参数中指定一个默认的的字符集,如果没指定,这个值继承自配置文件中的; 此时 character_set_server 被设定为这个默认的字符集; 当创建一个新的数据库时,除非明确指定,这个数据库的字符集被缺省设定为 character_set_server; 当选定了一个数据库时,character_set_database 被设定为这个数据库默认的字符集; 在这个数据库里创建一张表时,表默认的字符集被设定为 character_set_database,也就是这个数据库默认的字符集; 当在表内设置一栏时,除非明确指定,否则此栏缺省的字符集就是表默认的字符集; 这个字符集就是数据库中实际存储数据采用的字符集,mysqldump 出来的内容就是这个字符集下的; 当我们按照原来的方式通过PHP存取MySQL数据库时,就算设置了表的默认字符集为utf8并且通过UTF-8编码发送查询,你会发现存入数据库的仍然是乱码。问题就出在这个connection连接层上。 想要进行“正确”的存储和得到“正确”的结果,最方便的是在所有query开始之前执行一下: SET NAMES 'gbk'; 其中gbk是数据库字符集。 它相当于下面的三句指令: SET character_set_client = gbk; SET character_set_results = gbk; SET character_set_connection = gbk; 4.1和5.0默认使用的是latin1字符集(木头:妈的,老外真霸道,妄想让全世界都是使用瑞典字符集吗) 如果我们只想使用gbk字符集存储和获取数据, 我们在编译mysql 4.1和 5.0的时候,需要注意在my.ini或者my.cnf中添加两处参数 引用内容: [mysqld] default-character-set=utf8 引用内容: #settings for clients (connection, results, clients) [mysql] default-character-set=utf8 下面我们来说主题,如何转换数据库字符集 两种方法, 引用内容: 第一种----更改存储字符集 主要的思想就是把数据库的字符集有latin1改为gbk,big5,或者utf8; 以下操作必须拥有主机权限。假设当前操作的数据库名为:database 导出 首先需要把数据导为mysql4.0的格式,具体的命令如下: mysqldump -uroot -p --default-character-set=latin1 --set-charset=gbk --skip-opt databse > d4.sql mysqldump的参数参照: MySql数据库备份mysqldump参数选项 --default-characte-set 以前数据库的字符集,这个一般情况下都是latin1的, --set-charset 导出的数据的字符集,这个可以设置为gbk,utf8,或者big5 导入 首先使用下面语句新建一个GBK字符集的数据库(test) CREATE DATABASE `d4` DEFAULT CHARACTER SET gbk C然后把刚才导出的数据导入到当前的数据库中就ok了。 mysql -uroot -p --default-character-set=gbk -f d4<d4.sql 通过以上的导出和导入就把数据库的字符集改为正确的存储方式了。 其中d4为新建库的名称,d4.sql为导出文件的名字 但是这种方法,发现数据库数据存储量无端变大30%,真是郁闷 另外一种其实原理相同,但是需要手动操作,一般用于第一种方法失败后的选择 不过这种方法如果数据库很大,估计很难做,因为光打开文件就能让你死机 首先还是用phpmyadmin或者用mysql本身的dump导出 .sql文件 然后用UltraEdit打开你备份的所有xxxx.sql文件,查找 引用内容: DEFAULT CHARSET=latin1 latin1这里也许是别的,反正是你不想要的,要转成gbk或者big5的 字符集 把这个替换为“空” 在查找 引用内容: CREATE TABLE cdb_sessions ( sid char(6) character set latin1 collate latin1_bin NOT NULL default '', ip1 tinyint(3) unsigned NOT NULL default '0', ip2 tinyint(3) unsigned NOT NULL default '0', ip3 tinyint(3) unsigned NOT NULL default '0', ip4 tinyint(3) unsigned NOT NULL default '0', uid mediumint(8) unsigned NOT NULL default '0', username char(15) NOT NULL default '', groupid smallint(6) unsigned NOT NULL default '0', styleid smallint(6) unsigned NOT NULL default '0', invisible tinyint(1) NOT NULL default '0', `action` tinyint(1) unsigned NOT NULL default '0', lastactivity int(10) unsigned NOT NULL default '0', fid smallint(6) unsigned NOT NULL default '0', tid mediumint(8) unsigned NOT NULL default '0', nickname char(15) NOT NULL default '', UNIQUE KEY sid (sid) ) ENGINE=HEAP MAX_ROWS=1000; 替换为 引用内容: CREATE TABLE `cdb_sessions` ( `sid` char(6) binary NOT NULL default '', `ip1` tinyint(3) unsigned NOT NULL default '0', `ip2` tinyint(3) unsigned NOT NULL default '0', `ip3` tinyint(3) unsigned NOT NULL default '0', `ip4` tinyint(3) unsigned NOT NULL default '0', `uid` mediumint(8) unsigned NOT NULL default '0', `username` char(15) NOT NULL default '', `groupid` smallint(6) unsigned NOT NULL default '0', `styleid` smallint(6) unsigned NOT NULL default '0', `invisible` tinyint(1) NOT NULL default '0', `action` tinyint(1) unsigned NOT NULL default '0', `lastactivity` int(10) unsigned NOT NULL default '0', `fid` smallint(6) unsigned NOT NULL default '0', `tid` mediumint(8) unsigned NOT NULL default '0', `nickname` char(15) NOT NULL default '', UNIQUE KEY `sid` (`sid`) ) TYPE=HEAP MAX_ROWS=2000; 这一步更为简单的办法就是删除掉关于cdb_sessions表的这一段,将 来全新装一个d4,将这个表导出 将其内容复制,粘贴到 sql文件的最后面 保存后,再把这个sql文件导入到你的库中 就OK了 用这两种方法就可简单的过程就是 A导出4.1/5.0的库 B进行处理,转换成gbk字符集 C彻底卸载4.1或者5.0 D安装4.0.26 E然后导入处理完的库 降级的时候导出库可以用这个方法 mysqldump -uroot -p --default-character-set=latin1 --set-charset=gbk --skip-opt databse --compatible=mysql40 > d4.sql 这样导出的就是4.0的库勒 至于mysql版本的升级, 如果数据文件中有中文信息,那么将MySQL 4.0的数据文件,直接拷贝到MySQL 4.1中就是不可以的,即便在my.ini中设置了default-character-set为正确的字符集。虽然貌似没有问题,但MySQL 4.1的字符集有一处非常恼人的地方,以gbk为例,原本MySQL 4.0数据中varchar,char等长度都会变为原来的一半,这样存储中文容量不变,而英文的存储容量就少了一半。这是直接拷贝数据文件带来的最大问题。 所以,升级的根本,如果想使用“正确”的字符集,还是先用mysqldump导出成文件,然后导入。 ============================== 数据表编码整理工具 <?php $charset = ''; //字符集, 可选 'gbk', 'big5', 'utf-8' ################## 以下无须设置~~~ ##################################################################### define('IN_DISCUZ',TRUE); echo "<html>
"; echo "<head>
"; echo "<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
"; echo "<title>数据表整理工具</title>
"; echo "<style>
"; echo "body,table { font-size: 9pt;font-family:Tahoma, Verdana;background-color: #FFFFFF;line-height:150% }
"; echo "a { text-decoration: none }
"; echo "</style>
"; echo "</head>
"; echo "<body>
"; if (!@include './config.inc.php') { exit("抱歉!请将本程序放于您的论坛目录中运行!!"); } $tempfile = './forumdata/setnames_temp.php'; $action = isset($_GET['action']) ? $_GET['action'] : ''; $ntable = isset($_GET['ntable']) ? $_GET['ntable'] : ''; $step = isset($_GET['step']) ? $_GET['step'] : 0; $perptime = 2000; $discuzposts= $tablepre.'posts'; if (!in_array(strtolower($charset),array('gbk','big5','utf-8'))) { exit("抱歉!请设置您的 $charset 为正常值( 'gbk','big5','utf-8' 中的 一个)"); } $charset = strtolower(str_replace('-', '', $charset)); $collate = array('gbk'=>'gbk_chinese_ci','big5'=>'big5_chinese_ci','utf8'=>'utf8_gen eral_ci'); $character_collate = $collate[$charset]; echo "<span style='color:red'>设置相关库($dbname)、表、字段字符集 为: $charset </span><br>
"; mysql_connect($dbhost,$dbuser,$dbpw); mysql_select_db($dbname); if (empty($action)) { @unlink($tempfile); $tablesdata = ''; $i = 0; $query = mysql_query("SHOW TABLE STATUS LIKE '$tablepre%'") or exit(mysql_error()); while ($table = @mysql_fetch_array($query)) { if ($table['Name'] != $discuzposts) { $table } } if(!$fp = @fopen($tempfile, 'wb')) { exit("请确保本程序是放置于您的论坛目录下运行,且./forumdata存 在并可读写!!"); } @fwrite($fp, "<?php
if(!defined('IN_DISCUZ')) exit('Access Denied');
".$tablesdata."
?>"); @fclose($fp); echo "<b>用于整理数据库表字符集工具!!</b><br><br>
"; echo "请确定您的数据库内数据的字符集,并选择合适的Discuz!版本,然后使用本程序进行整理.<br>
"; echo "本程序仅适用于Discuz!4.0.0正式版之前的升级处 理.<br>
"; echo "如果您的论坛已经处于正常运行状态了,请切勿再随意使用本程序操作,否则将可能造成数据乱码!<br>
"; echo "<span style='color:#008000;font-weight:bold'>操作前强烈建议您备份好您的数据(比较建议使用直接COPY数据表文件方式备份).</span><br><br>
"; echo "<a href='setnames.php?action=set&step=0'>点击这里开始</a>"; exit; } if ($ntable != $discuzposts) { include @$tempfile; } if ($step == 0 && empty($ntable)) { if (mysql_query("ALTER DATABASE `$dbname` DEFAULT CHARACTER SET $charset COLLATE $character_collate")) { echo "论坛数据库: $dbname 字符集整理完毕!!<br><br>"; } else { exit("<span style='color:red'>论坛数据库整理操作失 败!!</span><br>".mysql_error()); } } if (isset($tables[$step]) && $ntable != $discuzposts) { $counts = count($tables); echo "当前操作: <b>$step / $counts</b> <br><br>
"; echo "<b>开始表: $tables[$step]</b> <br><br>
"; if (mysql_query("ALTER TABLE `$tables[$step]` DEFAULT CHARACTER SET $charset COLLATE $character_collate;")) { echo "整理表: $tables[$step] 操作完毕!<br>
"; } else { $perptime = 20000; echo "<span style='color:red'>整理表: $tables[$step] 操作失 败!!</span><br>
"; echo " <b>出错信息为:".mysql_error()."</b><br>
"; exit(); } $fieldquery = mysql_query("SHOW COLUMNS FROM `$tables[$step]`;") or exit("获取数据表 $tables[$step] 信息出 错!!<br>".mysql_error()); while ($field = mysql_fetch_array($fieldquery)) { if (in_array(strtolower(substr($field['Type'],0,4)),array('char','text','varc','enu m')) || strtolower(substr($field['Type'],0,10)) == 'mediumtext') { if (mysql_query("ALTER TABLE `$tables[$step]` CHANGE `$field[Field]` `$field[Field]` $field[Type] CHARACTER SET $charset COLLATE $character_collate;")) { echo " 字段: $field[Field] $field[Type] 整理操作完毕<br>
"; } else { $perptime = 20000; echo " <span style='color:red'>整理表 字段: $field[Field] $field[Type] 操作失败!!</span><br>
"; echo " 错误信息为: ".mysql_error()."<br>
"; exit(); } } } echo "<br>
"; $nextstep = $step + 1; $nexttable = isset($tables[$nextstep]) ? $tables[$nextstep] : $discuzposts; $url = "setnames.ph echo "<script>
"; echo "<!--
"; echo "function redirect() {
"; echo " window.location.replace('$url');
"; echo "}
"; echo "setTimeout('redirect();', $perptime);
"; echo "-->
"; echo "</script>
"; echo "自动进入下一个表( <b>$nexttable</b> )整理操作.<br><a href='$url'>如果页面不能自动跳转请点击这里.</a>"; } elseif ($ntable == $discuzposts) { $tableposts = isset($_GET['tableposts']) ? 1 : 0; if (empty($tableposts)) { echo "<script language="JavaScript">
"; echo "<!--
"; echo "function findobj(n, d) {
"; echo " var p, i, x;
"; echo " if(!d) d = document;
"; echo " if((p = n.indexOf("?"))>0 && parent.frames.length) {
"; echo " d = parent.frames[n.substring(p + 1)].document;
"; echo " n = n.substring(0, p);
"; echo " }
"; echo " if(x != d[n] && d.all) x = d.all[n];
"; echo " for(i = 0; !x && i < d.forms.length; i++) x = d.forms[i][n];
"; echo " for(i = 0; !x && d.layers && i < d.layers.length; i++) x = findobj(n, d.layers[i].document);
"; echo " if(!x && document.getElementById) x = document.getElementById(n);
"; echo " return x;
"; echo "}
"; echo "function copycode(obj) {
"; echo " var rng = document.body.createTextRange();
"; echo " rng.moveToElementText(obj);
"; echo " rng.scrollIntoView();
"; echo " rng.select();
"; echo " rng.execCommand("Copy");
"; echo " rng.collapse(false);
"; echo "}
"; echo "//-->
"; echo "</script>
"; echo "注意 : 由于 $discuzposts 可能数据过多,所以可能会导致操作超时或失败.<br>
"; echo " 如果您的数据不是很大或者为虚拟主机的话,可以使用本程序自动进行操作.<br>
"; echo " 否则,强烈建议您直接在您的主机上以MySQL命令行方式替代本程序的操作.<br><br>
"; echo "<li><a href='setnames.php?action=set&ntable=cdb_posts&tableposts=1'>如果您想使用本程序进行操作,请直接点击这里进行.</a><br><br></li>
"; echo "<li>如果您使用主机的MySQL命令行方式执行本操作,请使用如下5条语句(如果您有其他非标准结构的字段请自行整理):</li>
"; echo "<li><table border="1" cellpadding="2" cellspacing="1" style="border-collapse: collapse" bordercolor="#E0E0E0">
"; echo " <tbody>
"; echo " <tr>
"; echo " <td bgcolor="#F5F5F5" onclick="copycode(findobj('code1'));" style="cursor:hand"><b>点击 这里复制第 1 条语句:</b> </td>
"; echo " <td id="code1" style="padding-left:5px;font-size:11px">ALTER TABLE `$discuzposts` CHANGE `author` `author` varchar(15) CHARACTER SET $charset COLLATE $character_collate;</td>
"; echo " </tr>
"; echo " <tr>
"; echo " <td bgcolor="#F5F5F5" onclick="cop echo " <td id="code2" style="padding-left:5px;font-size:11px">ALTER TABLE `$discuzposts` CHANGE `subject` `subject` varchar(80) CHARACTER SET $charset COLLATE $character_collate;</td>
"; echo " </tr>
"; echo " <tr>
"; echo " <td bgcolor="#F5F5F5" onclick="copycode(findobj('code3'));" style="cursor:hand"><b>点击 这里复制第 3 条语句:</b> </td>
"; echo " <td id="code3" style="padding-left:5px;font-size:11px">ALTER TABLE `$discuzposts` CHANGE `useip` `useip` varchar(15) CHARACTER SET $charset COLLATE $character_collate;</td>
"; echo " </tr>
"; echo " <tr>
"; echo " <td bgcolor="#F5F5F5" onclick="copycode(findobj('code4'));" style="cursor:hand"><b>点击 这里复制第 4 条语句:</b> </td>
"; echo " <td id="code4" style="padding-left:5px;font-size:11px">ALTER TABLE `$discuzposts` CHANGE `message` `message` mediumtext CHARACTER SET $charset COLLATE $character_collate;</td>
"; echo " </tr>
"; echo " <tr>
"; echo " <td bgcolor="#F5F5F5" onclick="copycode(findobj('code5'));" style="cursor:hand"><b>点击 这里复制第 5 条语句:</b> </td>
"; echo " <td id="code5" style="padding-left:5px;font-size:11px">ALTER TABLE `$discuzposts` DEFAULT CHARACTER SET $charset COLLATE $character_collate;</td>
"; echo " </tr>
"; echo " </tbody>
"; echo "</table></li>
"; } else { echo "<b>开始表: $discuzposts</b> <br><br>
"; if (mysql_query("ALTER TABLE `$discuzposts` DEFAULT CHARACTER SET $charset COLLATE $character_collate;")) { echo "整理表: $discuzposts 操作完毕!<br>
"; } else { echo "<span style='color:red'>整理表: $discuzposts 操作失 败!!</span><br>
"; echo " <b>出错信息为:".mysql_error()."</b><br>
"; exit(); } $fieldquery = mysql_query("SHOW COLUMNS FROM `$discuzposts`;") or exit("获取数据表 $discuzposts 信息出 错!!<br>".mysql_error()); while ($field = mysql_fetch_array($fieldquery)) { if (in_array(strtolower(substr($field['Type'],0,4)),array('char','text','varc')) || strtolower(substr($field['Type'],0,10)) == 'mediumtext') { if (mysql_query("ALTER TABLE `$discuzposts` CHANGE `$field[Field]` `$field[Field]` $field[Type] CHARACTER SET $charset COLLATE $character_collate;")) { echo " 字段: $field[Field] $field[Type] 整理操作完毕<br>
"; } else { echo " <span style='color:red'>整理表字段: $field[Field] $field[Type] 操作失败!!</span><br>
"; echo " 错误信息为: ".mysql_error()."<br>
"; exit(); } } } echo "<br><br><br>
"; echo "<b>整理表完毕。请切记从服务器上删除本文件!!</b>"; echo "<br><br> [<a href='set } @unlink($tempfile); } else { @unlink($tempfile); echo "<b>整理表完毕。请切记从服务器上删除本文件!!</b>"; } ?>
信息发布:广州名易软件有限公司 http://www.myidp.net
|