MySQL 4.1迁移到MySQL 5.0版本的中文乱码问题解决
系统开过过程中,将数据库由MySQL 4.1转化到MySQL 5.0,在升级过程中遇到了中文乱码问题。先描述一下两边的服务器版本和环境。
原:Linux,mysql-standard-4.1.8-pc-linux-i686
新:Windows Server 2003,MySQL 5.0.45-community
本机客户端有两个:
MySQL AB\MySQL Connector/ODBC 3.51 = 3.51.22
MySQL AB\MySQL Connector/Net 5.0.8.1 = 5.0.8.1
原系统采用默认配置:
character_set_server latin1
character_set_database latin1
character_set_system utf8
character_set_client latin1
character_set_connection latin1
character_set_results latin1
校对字符集为(latin1_swedish_ci是latin1的默认校对)
collation_connection latin1_swedish_ci
collation_database latin1_swedish_ci
collation_server latin1_swedish_ci
character_set_system 元数据字符集
方案一:采用SQLyog等客户端连接MySQL4.1后dump出SQL,再Restore到MySQL 5.0。在执行过程中,发现dump出的SQL中中文数据为乱码。
后发现直接在客户端查询MySQL 4.1中文数据也是乱码,检查发现SQLyog连接后默认会执行SET NAMES 'utf8';导致取出的数据不能正常显示。尝试SET NAMES 'latin1',取出数据还是不能正常显示,但用客户端的导出数据功能时,发现已经是正常的中文,可客户端dump查询结果依旧无法显示中文。
方案二:ssh2上Linux服务器,用命令dump出转化后的utf8数据:
mysqldump --default-character-set=latin1 --character-sets-dir=utf8 -umysql -h10.1.47.6 -p ConfigV2Full > new080101.sql
将new080101.sql传到本地打开,发现已经是中文,遂将sql导入MySQL 5.0服务器,发现依旧乱码。但利用旧的连接器连接MySQL 5.0发现中文正常,字符集依旧是latin1。
方案三:在方案二的基础上,将new080101.sql另存为有Bom的utf8格式(用UltraEdit处理大文件有优势),再次导入,中文正常。此时字符集为utf8。
过程可谓相当曲折。依旧对MySQL4.1用latin1字符集存中文感到疑惑。于是又去阅读了MySQL 4.1的字符集处理一节,现作一个总结。
总结:
MySQL的使用者大量来自拉丁国家,可能这种字符集导致的乱码问题官方不够重视,也很测试到,简单搜索就会发现MySQL中文乱码问题频频产生。
但这不是MySQL设计者的初衷,MySQL 4.1字符集的设置是非常灵活的,其对于字符集的指定可以细化到一台机器、其中的一个数据库、其中的一张表、其中的一个字段,但是,普通开发者在创建数据库和数据表时,并没有进行那么复杂的配置,而一般使用默认配置。
默认的配置源头来自哪里呢?来自编译。
编译时,通常是Linux默认字符集latin1;
安装时,在配置文件中有一个默认字符集,如果不指定,则这个值继承自编译时;
启动时,可用命令行参数指定默认字符集,如果不指定,则这个值继承自配置文件;
此时character_set_server被设为这个默认字符集;
创建数据库时,如果不指定,则这个数据库的字符集被设为character_set_server;
选定数据库时,character_set_database被设定为这个数据库字符集;
创建一张表时,表的默认字符集被设为character_set_database
创建一个字段时,如果不指定,则设为表的默认字符集;
这个字符集才数据库中实际存储数据采用的字符集。就是说,如果保持默认,则所有的数据库的所有表的所有字段的都用latin1存储!
当客户端与MySQL建立连接后,发送给MySQL的数据采用的是什么字符集?
MySQL 无从得知 (它最多只能猜测),所以 MySQL 4.1 要求客户端必须指定这个字符集,也就是 character_set_client,MySQL 的怪异之处在于,得到的这个字符集并不立即转换为存储在数据库中的那个字符集,而是先转换为 character_set_connection 变量指定的一个字符集;转换为 character_set_connection 的这个字符集之后,还要转换为数据库默认的字符集,也就是说要经过两次转换;当这个数据被输出时,又要由数据库默认的字符集转换为 character_set_results 指定的字符集。
但服务器上的配置中character_set_client、character_set_connection、character_set_results都是latin1,所以说还是不明白它是如何保存中文的。我估计最大的可能是,它本身把中文当作latin1存入,客户端和连接器负责了把取出的latin1转为可正常显示的中文。
最后不得不说,MySQL将字符集细分的行为给非latin1语系开发者使用带来很大麻烦,MySQL将默认字符集设置为latin1也不够大气也不够智慧。开源是全球的,经济是全球的,世界是平的,以后的软件均使用utf8编码才是化繁就简的王道。
附录:很烦很复杂的MySQL字符集
character_set_server 服务器使用字符集
character_set_database 数据库使用字符集
character_set_system 系统内部元数据使用字符集,默认是utf8
character_set_client 客户端指定字符集
character_set_connection 连接时使用的字符集
character_set_results 返回结果的字符集
校对字符集的latin1_swedish_ci是latin1的默认值
collation_connection latin1_swedish_ci
collation_database latin1_swedish_ci
collation_server latin1_swedish_ci
http://www.cnblogs.com/likun/archive/2008/04/09/1144570.html