错误 1366:将字符串插入 MariaDB 时字符串值不正确

Error 1366: Incorrect string value when inserting strings into MariaDB

我有具有索引 VARCHAR(10) NOT NULL COLLATE 'utf8mb3_general_ci' 类型的 MariaDB table。我在 Go 中有一个字符串,我将其切成 10 个字符,如果它更长,则插入 into/update 这个 table。我将字符串剪切为:

if len(value) > 10 {
  value = value[:10]
}

现在我遇到了以 š 字符结尾的字符串的问题。 MariaDB 抛出错误:Error 1366: Incorrect string value: '\xC5'。查找 unicode tables,这个字符表示为 \xc5\xa1 这让我相信字符串的切割不知何故使数据库无法消化字符串?

我想避免在我的代码中处理 utf8/unicode,因为这需要遍历所有数据库方法并处理所有字符串。而且我不认为这是必要的,因为我以前从未需要过它。所以我认为问题出在其他地方,但不确定在哪里。

我尝试将排序规则切换为 utf8mb4_general_ci,但这也无济于事。

有趣的是,如果我直接使用 HeidiSQL 编辑该列,则字符串仅保存 fine.Which 让我相信这可能是驱动程序问题。我一如既往地使用 github.com/go-sql-driver/mysql。所以我不希望出现问题,但谁知道呢...

which makes me believe the cutting of the string somehow makes the string indigestible for the database?

通过细分为 value[:10] 来切割字符串(并使用 len 测量长度)总是 如果您的程序有任何错误处理多字节字符的机会。这是因为对字符串进行索引操作是对其字节进行操作,这可能是也可能不是多字节编码的一部分。

如您所见,字符 š 在 UTF-8 中编码为 \xc5\xa1。如果这两个字节出现在 value 字符串中索引 910 处,您的索引表达式 [:10] 会破坏数据。

字符集utf8mb3utf8mb4仅将允许的UTF-8范围分别限制为3字节和4字节字符,但\xc5不是有效的UTF- 8 开始,所以无论哪种方式都会被拒绝。

在 MariaDB 中,数据类型为 VARCHAR(N) 的列计数 个字符 (由排序规则指定)。您想要在第十个字符而不是第十个字节处剪切 value 字符串。

I would like to avoid handling utf8/unicode in my code

您已经通过将 MariaDB 归类声明为 utf8mb3 来承认 UTF-8。将代码中的输入数据正确处理为 UTF-8 是合乎逻辑的。要在第 n 个字符(或 rune,在 Go 中代表一个 Unicode 代码点)处剪切,您可以使用类似的东西:

// count the runes
if utf8.RuneCountInString(value) > 10 {
  // convert string to rune slice
  chars := []rune(value)
  // index the rune slice and convert back to string
  value = string(chars[:10])
}

这不会破坏 UTF-8 编码,但是请记住,它会执行更多分配并且不考虑组合字符,例如当涉及到加入者 200D 时。