Umlaut问题 - 如何成功备份和恢复MySQL数据库与特殊字符使用MySQLDumper

Umlaut问题 - 如何成功备份和恢复MySQL数据库与特殊字符使用MySQLDumper 有很多论坛...

Umlaut问题 - 如何使用MySQLDumper成功备份和还原具有特殊字符的MySQL数据库

介绍

本文由MySQLDumper开发人员Daniel Schlichtholz撰写 ,这是用于备份和恢复数据库的免费且有用的脚本。 原来的语言是德语,我把它翻译成英文,因为有人用其他语言的变音符和其他特殊字符来阅读这篇文章。 原文可以在德文中找到

Umlaut问题:

有很多论坛有一些麻烦的变音单或其他特殊字符的报告错误地显示。 尝试帮助来自许多方面,但几乎没有任何人似乎有一个真正完整的问题的图片。 即使是网络主机的支持热线似乎也达到了这一点。 有不可思议的半真相。 在某些情况下,他们证明是正确的,但并不能帮助所有人。 只是因为设置变化很大。

在我作为MySQLDumper开发人员的角色中,我自然花了很多时间来评估这种情况。 我现在相信能够提供一个完整的概述,涵盖这个问题的不同方面。 很多,我的意思是很多研究已经进入了本文的解释。

请警告:事情不简单,不能在2分钟内解释!

有一个原因,为什么在许多论坛的帮助的呼喊正在堆积,几乎没有人真的可以帮助。 如果您正在寻找一个简单的解释(“我在哪里点击使其正常工作”),请不要再打扰了。 这篇文章很长,需要接受。 你所得到的是彻底了解问题。

找到正确的信息是一项非常困难的任务。 所以在我自己终于明白这件事之前花了一些时间。 我想救你这个奥德赛 - 任何处理这个问题的人都知道我在说什么。
不用说,我不是所有智慧的主人 - 我将在这里解释的方面很大程度上取决于通过检查许多MySQLDumper用户的各种不同服务器所获得的经验(感谢您的信任)。 如果你知道这里没有提到的一个方面,我请你让我知道。

理论 - 为什么发生变音问题?

简单来说,它是由不同的MySQL-Server版本使用不同的标准字符集引起的。

过去,当脚本(任何脚本)向MySQL服务器发送或接收数据时,该数据始终以latin1编码(至少在德国)。 数据库备份程序(例如MySQLDumper)接收该数据,并将其作为SQL命令保存在文本文件中。

到现在为止还挺好。

但是:由脚本写在服务器上的文本文件没有可用的编码。 这意味着一个脚本无法知道什么字符集,它放在文件中的数据被编码。有许多不同的字符集,所以完全相同的数据可以以许多不同的方式传输,取决于它编码的字符集。

文本编辑器可以通过在文件的开头插入一个特殊的标识符来标记utf8编码的文本文件 - 一个所谓的BOM(字节顺序标记 - 参见关于BOM的维基百科文章正式的Unicode解释 )。

Web服务器或PHP解释器无法读取该标记,因此它将数据传递到Web浏览器不变 - 这当然不是您想要的。 所以这种识别字符集的方式落在了底下,并创建了一个“未标记”的文本文件。 所以它是未知哪个字符集的文件被编码。 这就是整个问题所在。

MySQL版本3.x在latin1中保存和提供数据(因为至少在德国,通常是如何安装的)。 没有脚本或用户可以做的 - 输出总是latin1。 因此,MySQL-Server版本3.x的备份文件总是包含以latin1编码的数据。 同样地,它总是期望接收的数据被编码在latin1中。 在备份文件的数据库还原过程中,MySQLDumper逐行读取文件。 它识别MySQL命令的开始和结束,提取它并将其发送到MySQL-Server不变。 所以在这种情况下,一切都很好。
备份文件是latin1,MySQL期望latin1 - >工作! 在这种情况下,没有变音问题。

所以,如果一切都如此奇妙,为什么他们开始改变事情?

有很多语言特定的字符不能使用1字节字符集显示。 德语umlautsöüä在其他字符集中没有找到,因此来自日本的用户(例如)将会遇到德国网站的麻烦。 这可能导致变音符显示不正确。

这导致了很多与编程有关的问题。 想想多语言程序或多语言网站。 网站的每种语言变体都必须输出语言各自字符集中的所有文本。 必须发送不同的标题,以便浏览器甚至可以实现应该显示的语言。 此外,必须在浏览器中安装相关的字符集。 与此相关的问题列表将会很长,并会给开发人员带来许多复杂的问题。

因此,希望能够输出所有语言的所有字符,只有一个字符集,以避免所有这些问题。 这就是为什么开发了Unicode字符集: 有关Unicode的维基百科文章,请参阅此处

但是,当然,您需要更多的内存空间才能在一个字符集中显示大量可能的字符。 为了补偿额外的内存负载,开发了不同的存储和显示格式。 其中最着名的是UTF8 。 UTF代表“Unicode转换格式”,并且能够减少必要的内存空间,只允许一些字符需要多个字节来显示。 许多常见的字符仍然只需要1个字节。

现在我们来到实际的部分!

因为4.0版MySQL使用utf8来在内部存储数据。 然而,这并不意味着开发人员只能创建在utf8中对数据进行编码的程序。 因为MySQL可以以您想要的任何格式传送数据。

我们需要做的就是告诉服务器,我们希望它为数据提供什么样的格式,当然我们发送的数据是什么格式的编码! 为了实现这一点,程序可以在连接到MySQL服务器之后发送命令SET NAMES latin1 。 因此,程序和MySQL-Server同意在latin1中交换数据。 当程序将数据发送到MySQL-Server MySQL时,会收到数据为latin1,将其内部转换为utf8,并将其正确存储。 当脚本需要数据时,MySQL加载数据并将其转换为latin1,然后再提供给它。

所以当两人同意一个字符集时,通信就会很好地工作,因为他们字面上讲的是相同的语言。

如果连接到MySQL服务器的程序没有说明服务器应该使用什么字符集,则会使用默认字符集(在MySQL-System-Variable character_set_connection中声明 )。
而这正是出现错误的地方,如果数据是按照程序期望的格式发送的。
这是一条双向街道:
如果程序假定它接收到latin1编码的数据,但服务器的默认字符集设置为utf8,那显然不太合适。 当脚本将数据发送到MySQL服务器时也是一样。

大多数脚本还没有解决这种情况,必须声明字符集(包括直到并包括1.21b6的版本中包括MySQLDumper)。
而这是出现问题的地方,因为有些服务器的标准字符集是latin1。 与其他人一样,它是utf8和其他人再次是完全不同的。 我们来看看使用MySQLDumper 1.21b6的做法:

情景1:

  • - 从MySQL 3.x转移到4.x,较新的使用latin1作为标准字符集。 - MySQL 3.x数据库的备份编码为latin1。
  • - 在数据库恢复过程中,Dumper 1.21(不知不觉)将数据发送到在latin1编码的MySQL服务器。
  • - MySQL收到数据,并希望它是latin1,因为没有别的。 然后将数据转换为utf8并将其正确存储,因为标准字符集与从Dumper 1.21接收到的数据的字符集相匹配。
  • - 一切都OK。 Umlauts和其他特殊字符正在工作。

情景2:

  • - 从MySQL 3.x转移到4.x,较新的使用utf8作为标准字符集。
  • - MySQL 3.x数据库的备份编码为latin1。
  • - 在数据库恢复过程中,Dumper 1.21(不知不觉)将数据发送到以latin1编码的MySQL服务器
  • - MySQL接收数据并认为“嘿,很酷,没有特殊的字符集被声明,所以我得到utf8编码数据,我不需要转换它,所以我可以立即将它存储在数据库。 “
  • - 现在MySQL正在将latin1编码的数据保存为utf8!
  • - 如果它们没有正确转换,那么在utf8中看到的编码latin1的特殊字符没有对应的,它们被显示为问号或同样恼人的东西。
  • - 所以在这里出错,特殊字符显示为问号或矩形或任何。

情景3 *:

  • - 从MySQL> = 4.1转换为> = 4.1,旧服务器使用utf8作为标准字符集,新的使用latin1作为标准字符集。
  • - 所以旧服务器的备份文件被编码为utf8,因为当转储备份文件时,没有指定其他格式,旧的MySQL服务器以标准字符集(utf8)发送数据。
  • - 在数据库恢复过程中,Dumper 1.21(不知不觉)将数据发送到utf8编码的MySQL服务器。
  • - MySQL接收并保存utf8编码数据作为latin1编码数据。
  • - 现在utf8需要特殊字符的多个字节,但是这些相同的字符在latin1中被评估为1个字节的字符。
    结果,一个特殊字符在显示时变成2(或更多)字母/字符。
  • - 所以当从新数据库检索数据并显示数据时,变音符可能如下所示:äöü(这等于äöü)。 Ä实际上是在utf8中的某些特殊字符之前的代码,但不会以这种方式解释,因为MySQL-Server假定数据被编码为latin1。 再次出现这种情况。

*(编辑:对于案例3的情况,我制定了一个修正程序,请参阅: http : //www.mysqldumper.de/board/viewtopic.php? p= 19187#19187