将 charset latin1 中的数据从 MySQL 5.7 迁移到 8.0 时出现问题

Issue when migrating data in charset latin1 from MySQL 5.7 to 8.0

提问人:Vitaly Radchik 提问时间:5/2/2023 最后编辑:Vitaly Radchik 更新时间:5/4/2023 访问量:286

问:

当我将 AWS RDS 中托管的 MySQL 数据库从版本 5.7 升级到 8.0 时,我的公司遇到了一个令人不快的问题。

最初,我们有 MySQL 5.7,之前的开发团队保留了字符集和排序规则的默认值。Charset 是 ,排序规则是 。PHP 和 Node.JS 应用程序使用此数据库来存储数据,而无需任何编码转换。两者都工作正常,存储包含非拉丁字符的数据,例如货币符号和非拉丁语言。latin1latin1_swedish_ci

当我们使用 AWS 蓝/绿更新将 MySQL 引擎版本升级到 8.0 时,问题就开始了。数据保持不变,但所有非拉丁字符都开始显示为问号 (????) 或乱码。将字符集更改为 和 排序规则 为 无济于事。数据似乎没有变化,即使在发出命令或 时也返回了乱码。utf8mb4utf8mb4_900_ai_ciSET NAMES utf8SET NAMES utf8mb4

更糟糕的是,在将表转换为 后,进入客户端数据库的数据似乎已损坏(再次出现问号和胡言乱语)。以前保存的数据也变得不可读。 似乎唯一有帮助的是发出命令。之后,我们获得了大部分数据,但一些字符,如欧元符号 (€) 和来自不同语言的其他字符,不能正确存储在数据库中。 奇怪的是,€-之前存储在MySQL 5.7中,没有问题和命令。utf8SET NAMES latin1SET NAMES ...

我读过类似的主题,描述如何转换表字符集和排序规则,但问题是我们可以使用 SQL 语句转换表,但数据仍未转换。因此,即使在转换后,它也会返回胡言乱语。

另外,我想提一下,在我们尝试使用 MySQL 命令转换数据时,我们遇到的情况是,现在部分数据使用 utf8 进入数据库,然后无法转换回(通过 BLOB 字段执行转换)。它现在返回错误。有谁知道如何转换那些值而不将数据库带回?CONVERT TO CHARACTER SETlatin1Illegal character \xXXlatin1

更新: 这是以下结果:Query results表已经有字符集(我们运行)。但正如你所看到的,数据没有被转换。所有行都应具有该值,但只有一行具有正确的值。 问题在于,在将表转换为 后,无论SELECT id, format, HEX(format) FROM storesutf8mb4ALTER TABLE stores CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci€{{amount_with_comma_separator}}utf8mb4SET NAMES [utf8|latin1]

我将不胜感激。

MySQL 数据转换 ISO-8859-1 UTF8MB4

评论

0赞 JosefZ 5/2/2023
这回答了你的问题吗?如何更改整个数据库的字符集(和排序规则)?
0赞 Vitaly Radchik 5/2/2023
@JosefZ不,问题在于数据本身仍未转换。仅表元数据。
0赞 Rick James 5/3/2023
请参阅 stackoverflow.com/questions/38363566/ 中的“问号”(而不是“黑钻石”)...如果您想进一步讨论,请提供 SHOW 和 SELECT HEX(..) 以协助分析。
0赞 Vitaly Radchik 5/3/2023
@RickJames谢谢,在原始帖子中添加了输出。SELECT HEX()

答:

1赞 Rick James 5/4/2023 #1

坏消息。

c3a2e2809ac2ac  is the "double encoding" for Euro.
e282ac  (in line 811) is the correct UTF-8 encoding for Euro

通常,客户搞砸了,但有时它做对了。

如果您看到“????”,那是另一个问题。

所以(还不是完整的答案)......

  • 修复代码,同时修复表定义。这需要特殊的代码来以一种方式处理 811,而以另一种方式处理其他方式。
  • 修复客户端,使其在插入时不会弄乱东西。
  • 修复客户端,使其看不到????.通常在表格中插入问号。你看到的是你这里的文字吗?(我认为不是。

请阅读 UTF-8 字符的麻烦;我看到的不是我存储的

找到 、 转换代码 、 、 连接参数等。SET NAMESSHOW CREATE TABLE

评论

0赞 Vitaly Radchik 5/6/2023
是的,谢谢。问题是,首先,我们做的是运行命令,然后才意识到我们只有在 put 时才能读取旧数据。但是我们无法将表转换回,因为错误的字符被写入了表。所以现在我们有了连接和表编码。ALTER TABLE table_name CONVERT TO utf8mb4 COLLATE utf8mb4_general_ciSET NAMES latin1latin1SET NAMES latin1utf8mb4
0赞 Rick James 5/6/2023
唉,应用“错误”的修复可能会使事情变得更糟。