MySQL - 更新时无效的 utf8mb4 字符串

Posted

技术标签:

【中文标题】MySQL - 更新时无效的 utf8mb4 字符串【英文标题】:MySQL - Invalid utf8mb4 character string on update 【发布时间】:2015-04-14 05:56:03 【问题描述】:

我的问题和这里发现的几乎一模一样

mysql - 1300 - Invalid utf8 character string on update

没有提出任何解决方案,并且该人的帮助(创建临时表)似乎没有帮助。这是我正在使用的选择语句:

SELECT
    CONVERT(line_1 USING utf8mb4),
    CONVERT(line_1 USING latin1),
    HEX(line_1)
FROM address
WHERE ((CAST(CONVERT(line_1 USING latin1) AS CHAR)) <> (CAST(line_1 AS CHAR)))
    AND CONVERT(line_1 USING utf8mb4) IS NULL;
+-------------------------------+------------------------------+----------------------------------------------------+
| CONVERT(line_1 USING utf8mb4) | CONVERT(line_1 USING latin1) | hex(line_1)                                        |
+-------------------------------+------------------------------+----------------------------------------------------+
| NULL                          | Högbergsgatan 97             | 48F6676265726773676174616E203937                   |
| NULL                          | Zücherstrasse 161            | 5AFC636865727374726173736520313631                 |
| NULL                          | 2275, Rue de l'Université    | 323237352C20527565206465206C27556E69766572736974E9 |
| NULL                          | Högbergsgatan 97             | 48F6676265726773676174616E203937                   |
+-------------------------------+------------------------------+----------------------------------------------------+

当我尝试运行以下更新命令时,我得到:

UPDATE address
SET line_1 = CONVERT(CAST(CONVERT(line_1 USING latin1) AS CHAR) USING utf8mb4)
WHERE (CAST(CONVERT(line_1 USING latin1) AS CHAR) <> CAST(line_1 AS CHAR))
    AND CONVERT(line_1 USING utf8mb4) IS NULL;
ERROR 1300 (HY000): Invalid utf8mb4 character string: 'F66762'

我尝试通过以下方式设置线路,都产生相同的错误:

SET line_1 = CAST(CONVERT(line_1 USING latin1) AS CHAR)
SET line_1 = CONVERT(line_1 USING latin1)

我还查看了http://jonisalonen.com/2012/fixing-doubly-utf-8-encoded-text-in-mysql/,看看是否可能是双重编码问题,但这些都不起作用,而且我一直收到相同的字符串错误。

此外,我查看了https://mathiasbynens.be/notes/mysql-utf8mb4 以帮助完成转换步骤,但 utf8mb4 和 utf8 导致完全相同的问题。 (起初我以为是 utf8 的东西,所以我改用 utf8mb4,当我仍然遇到同样的问题时,我知道有更深层次的问题)

如您所见,发生了一些奇怪的事情。查看我的 show create address 表,我可以验证字符集是否设置正确:

SHOW CREATE TABLE address;
| address | CREATE TABLE `address` (
  `addressid` bigint(20) NOT NULL AUTO_INCREMENT,
  `addressuuid` char(32) COLLATE utf8mb4_unicode_ci NOT NULL,
  `line_1` blob,
  PRIMARY KEY (`addressid`)
) ENGINE=InnoDB AUTO_INCREMENT=48970 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='All potential addresses' |

此外,您可以在我的实例中看到我的字符变量是正确的:

mysql> show variables like 'char%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8mb4                    |
| character_set_connection | utf8mb4                    |
| character_set_database   | utf8                       |
| character_set_filesystem | binary                     |
| character_set_results    | utf8mb4                    |
| character_set_server     | utf8mb4                    |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)

我是怎么到这里的

因此,提供有关该问题的一些背景信息可能会有所帮助,以防万一它是导致问题的背景。

我有一个最初设置为 latin1 编码所有内容的数据库。然后我运行了以下代码:

SET NAMES 'latin1';

/* We must change things to blob and then back again */
ALTER TABLE `address` CHANGE line_1 line_1 BLOB;
ALTER TABLE `address` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `address` CHANGE line_1 line_1 VARCHAR(64);

切换到 blob 然后再回到 varchar 的原因是正常的推荐过程。 (www.percona.com/blog/2013/10/16/utf8-data-on-latin1-tables-converting-to-utf8-without-downtime-or-double-encoding/)

让我知道这是否有帮助,以及是否可以提供更多信息。我使用的是 MySQL 5.6,所以理论上它应该可以更好地处理事情,但谁知道呢。由于只有 4 行,我可以手动更新每一行,但理论上存在更大的潜在问题,而且由于我实际上还有很多列要查看,所以最好确保我有一个实用的方法来处理这些情况,以防我得到很多行的东西。

【问题讨论】:

首先做一个SELECT HEX(col), col ...,这样我们就可以看到该领域的内容。目标是什么?换桌子?或者只是出去Högbergsgatan之类的东西? 我在上表中添加了十六进制。目标是能够将所有内容从旧字符编码转换为新字符编码。但是我尝试的每种方法似乎都存在字符串无法转换/无效字符串的问题。 你做对了吗?我有同样的问题。 不幸的是,似乎没有什么能正常工作,因为有些东西是双重编码的,有些是单一的,它变得一团糟。幸运的是,我们的数据库并没有太大,所以我最终不得不导出我们的数据库,然后我手动更新了所有错误的字符,修复了表上的编码,然后重新导入。从那以后就没有遇到过麻烦,但这并不好玩=/ 【参考方案1】:

由于line_1 是一个blob,而不是文本字段,MySQL 无法控制其中的“字符”,也不关心它是否是非文本信息(例如JPG)。在您提供的示例中,字段中有 latin1 文本(例如,十六进制 F6 表示 ö)。因此,CONVERT(line_1 USING latin1) 工作“很好”。

我不明白你的目标。您是否尝试将 BLOB 读取为 TEXT?如果是这样,如果所有非ascii字符都被编码为latin1,那么那个CONVERT就是答案。

如果你的目标是别的东西,那么让我们从那里开始吧。

它不是“双重编码”的,所以它们都不起作用。

ALTER TABLE address CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

执行SHOW CREATE TABLE address 并检查line_1 的字符集。

【讨论】:

所以最初该字段设置为 VARCHAR(64)。目标是将数据库从 latin1 转换为 utf8mb4。所以我将名称设置为 latin1,将字段更改为 blob,转换字符集,然后尝试转换回 varchar(64)。当我尝试转换回来时,出现以下错误:字符串值不正确:'\xF6gberg...' for column 'line_1' at row 7578 2-step-alter-thru-blob 用于字节不符合声明的情况。 1-step-ALTER-CONVERT 可能是您需要的。 (或者这似乎是您现在需要的。)所以,我认为您需要从当前 BLOB 中使用 latin1 字节执行 3 个步骤:SET latin1、ALTER to VARCHAR、ALTER CONVERT。 “修复”的比较:mysql.rjweb.org/doc.php/charcoll#fixes_for_various_cases

以上是关于MySQL - 更新时无效的 utf8mb4 字符串的主要内容,如果未能解决你的问题,请参考以下文章

SQLAlchemy 报告 BINARY 列的“无效的 utf8mb4 字符串”

如何调试 Etherpad Lite 数据库中 MySQL utf8mb4 列中的无效数据

1300, "无效的 utf8mb4 字符串:'\\xE2\\x96\\x88\\xE2\\x96\\x88

android emoji可以存入MYSQL,但是IOS EMOJI表情存入不成功,会报错,mysql已经支持utf8mb4

如何在mysql中存取utf8mb4编码的字符

mysql 设置 utf8mb4 怎么查询