可怕的 MySQL 导入编码问题 - 重新审视
Posted
技术标签:
【中文标题】可怕的 MySQL 导入编码问题 - 重新审视【英文标题】:The dreaded MySQL import encoding issue - revisited 【发布时间】:2011-08-24 11:46:03 【问题描述】:我遇到了标准 mysql 导入编码问题,但似乎无法解决。
我的客户已经运行了一段时间的 WordPress 安装。我已将数据库转储到文件中,并在本地导入。生成的页面中到处都是 � 字符。
我检查了双方的数据库属性: 制作:show create database wordpress;
CREATE DATABASE `wordpress` /*!40100 DEFAULT CHARACTER SET latin1 */
本地:显示创建数据库 wordpress;
CREATE DATABASE `wordpress` /*!40100 DEFAULT CHARACTER SET latin1 */
生产:显示创建表 wp_posts;
CREATE TABLE `wp_posts` (
`ID` bigint(20) unsigned NOT NULL auto_increment,
...
KEY `post_date_gmt` (`post_date_gmt`)
) ENGINE=MyISAM AUTO_INCREMENT=7932 DEFAULT CHARSET=utf8
本地:显示创建表 wp_posts;
CREATE TABLE `wp_posts` (
`ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
...
KEY `post_date_gmt` (`post_date_gmt`)
) ENGINE=MyISAM AUTO_INCREMENT=7918 DEFAULT CHARSET=utf8
我已经花了几个小时阅读有关如何压缩 � 的论坛,但我什么也做不了。 99% 的答案说要匹配数据库之间的字符集。如果满足以下条件,我认为应该可行:
mysqldump --opt --compress --default-character-set=latin1 -uusername -ppassword wordpress | ssh username@anotherserver.net mysql --default-character-set=latin1 -uusername -ppassword wordpress
我也使用 utf8 字符集完成了它。仍然是�的。
我尝试直接修改 SQL 转储,将 utf8 或 latin1 放在“SET names UTF8”行中。仍然是�的。
奇怪的症状
我希望这些 � 字符会出现在内容中的特殊字符的位置,例如 ñ 或 ö,但我已经在通常出现的地方看到了只是一个空间。我还看到它代替撇号(但不是所有撇号)、双引号和商标符号。
� 标记非常罕见。它们平均每页出现三到四次。
通过 Sequel Pro(本地或实时)查看数据库时,我没有看到任何 �。通过 Textmate 查看时,我在 SQL 中没有看到任何 �。
我错过了什么?
编辑
更多信息:
我试图确定实时数据库认为编码是什么。我跑了show table status
,似乎排序规则是utf8_general_ci,
utf8_binand
latin1_swedish_ci`的混合。它们有什么不同?有关系吗?
我也跑了:show variables like "character_set_database"
,得到了latin1
;
【问题讨论】:
【参考方案1】:这就是我最终解决问题的方式:
第一个mysqldump -uusername -ppassword --default-character-set=latin1 database -r dump.sql
然后运行这个脚本:
$search = array('/latin1/');
$replace = array('utf8');
foreach (range(128, 255) as $dec)
$search[] = "/\x".dechex($dec)."/";
$replace[] = "&#$dec;";
$input = fopen('dump.sql', 'r');
$output = fopen('result.sql', 'w');
while (!feof($input))
$line = fgets($input);
$line = preg_replace($search, $replace, $line);
fwrite($output, $line);
fclose($input);
fclose($output);
脚本查找所有大于 127 的十六进制字符并将它们编码到它们的 html 实体中。
然后mysql -uusername -ppassword database < result.sql
【讨论】:
非常感谢,这解决了我的问题!这两天我一直在研究这该死的东西。我试图获取土耳其语数据库的副本,其中包含“特殊”重音字符。当我导入它时,无论特殊字符在哪里,它都会崩溃。我以 latin1 字符集导出,在上面运行了这个脚本,然后就很好地导入了它。我想我实际上也导入了 latin1 字符集,但它有效!再次感谢伙计。【参考方案2】:较旧的 WordPress 数据库甚至较新的 WordPress 数据库的一个常见问题是数据库表被设置为 latin-1,但内容实际上被编码为 UTF-8。如果您尝试导出为 UTF-8,MySQL 将尝试将(假定的)Latin-1 数据转换为 UTF-8,从而导致双重编码字符,因为数据已经是 UTF-8。
解决方案是将表格导出为 latin-1。由于 MySQL 认为它们已经是 latin-1,它会直接导出。
将字符集从“latin1”更改为“utf8”。 由于转储的数据在导出过程中没有进行转换,实际上是UTF-8编码的数据。
将新表创建为 UTF-8 如果 CREATE TABLE 命令在 SQL 转储文件中,请将字符集从“latin1”更改为“utf8”。
正常导入您的数据。由于您的转储文件中有 UTF-8 编码的数据,因此转储文件中声明的字符集现在是 UTF-8,而您要导入的表是 UTF-8,一切都会顺利进行
【讨论】:
听起来和正在发生的事情一模一样。 我尝试了您概述的过程。出口:mysqldump --default-character-set=latin1 -u username -ppassword wordpress > dump-20110512.sql
。导入:mysql -uusername -ppassword wordpress < dump-20110512.utf8-1.sql
。现在,在任何包含 � 的字段中,它们在第一个 � 处被截断。导入似乎运行没有错误。当我检查 SQL 文件时,我用作参考的 INSERT 语句似乎是完整的。我相信恶作剧的角色仍然存在。我看到文本 应该是撇号。
我将 SQL 文件中的每个 latin1 实例更改为 utf8。包括 CREATE TABLE 语句末尾的一些语句,其中有:ENGINE=MyISAM AUTO_INCREMENT=635 DEFAULT CHARSET=latin1;【参考方案3】:
我可以通过如下修改我的 wp-config.php 来解决这个问题:
/** Database Charset to use in creating database tables. */
define('DB_CHARSET', 'utf8');
/** The Database Collate type. Don't change this if in doubt. */
define( 'DB_COLLATE', 'utf8_general_ci' );
【讨论】:
花了 3 个小时寻找解决方案。转储数据库并恢复多次,但均未成功。这 2 个常量拯救了我的一天!【参考方案4】:我认为您可以通过这种方式解决此问题:
$link = mysql_connect('localhost', 'mysql_user', 'mysql_password');
$db = mysql_select_db('mysql_db', $link);
mysql_query('set names utf8', $link);
【讨论】:
mysql_*
函数已弃用,您应该使用 PDO。以上是关于可怕的 MySQL 导入编码问题 - 重新审视的主要内容,如果未能解决你的问题,请参考以下文章
当我们重新导入时,jar 文件是不是会更改编码文本文件的内容?
MySQL学习-- 0x02 .sql 文件导入及编码问题解决