可怕的 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 转储,将 utf8latin1 放在“SET names UTF8”行中。仍然是�的。

奇怪的症状

我希望这些 � 字符会出现在内容中的特殊字符的位置,例如 ñö,但我已经在通常出现的地方看到了只是一个空间。我还看到它代替撇号(但不是所有撇号)、双引号和商标符号。

� 标记非常罕见。它们平均每页出现三到四次。

通过 Sequel Pro(本地或实时)查看数据库时,我没有看到任何 �。通过 Textmate 查看时,我在 SQL 中没有看到任何 �。

我错过了什么?

编辑

更多信息:

我试图确定实时数据库认为编码是什么。我跑了show table status,似乎排序规则是utf8_general_ci,utf8_binandlatin1_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 文件导入及编码问题解决

php连mysql用 utf-8编码乱码怎么办

Gstreamer:如何在不重新编码的情况下将 rtpvp8depay 导入 webmmux?

mySQL编码问题