本节介绍在 utf8mb3 和 utf8mb4 字符集之间转换字符数据时可能会遇到的问题。
此讨论主要集中在 utf8mb3 和 utf8mb4 之间的转换,但类似的原则也适用于在 ucs2 字符集和 utf16 或 utf32 等字符集之间转换。
utf8mb3 和 utf8mb4 字符集的差异如下
- utf8mb3仅支持基本多语言平面 (BMP) 中的字符。- utf8mb4还支持位于 BMP 之外的补充字符。
- utf8mb3每个字符最多使用 3 个字节。- utf8mb4每个字符最多使用 4 个字节。
此讨论指的是 utf8mb3 和 utf8mb4 字符集名称,以明确区分 3 字节和 4 字节 UTF-8 字符集数据。
从 utf8mb3 转换为 utf8mb4 的一个优势是,这使应用程序能够使用补充字符。一个权衡是,这可能会增加数据存储空间需求。
就表内容而言,从 utf8mb3 转换为 utf8mb4 没有任何问题
- 对于 BMP 字符, - utf8mb4和- utf8mb3具有相同的存储特性:相同的代码值、相同的编码、相同的长度。
- 对于补充字符, - utf8mb4需要 4 个字节来存储它,而- utf8mb3根本无法存储该字符。当将- utf8mb3列转换为- utf8mb4时,您无需担心转换补充字符,因为不存在补充字符。
就表结构而言,以下是最主要的潜在不兼容性
因此,要将表从 utf8mb3 转换为 utf8mb4,可能需要更改某些列或索引定义。
可以使用 ALTER TABLE 将表从 utf8mb3 转换为 utf8mb4。假设一个表具有以下定义
CREATE TABLE t1 (
  col1 CHAR(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci NOT NULL,
  col2 CHAR(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL
) CHARACTER SET utf8mb3;以下语句将 t1 转换为使用 utf8mb4
ALTER TABLE t1
  DEFAULT CHARACTER SET utf8mb4,
  MODIFY col1 CHAR(10)
    CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
  MODIFY col2 CHAR(10)
    CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;从 utf8mb3 转换为 utf8mb4 时需要注意的是,列或索引键的最大长度在 字节 方面保持不变。因此,它在 字符 方面更小,因为字符的最大长度为 4 个字节,而不是 3 个字节。对于 CHAR、VARCHAR 和 TEXT 数据类型,在转换 MySQL 表时,请注意以下问题
- 检查所有 - utf8mb3列的定义,并确保它们不超过存储引擎的最大长度。
- 检查所有对 - utf8mb3列的索引,并确保它们不超过存储引擎的最大长度。有时,最大值会因存储引擎增强而发生变化。
如果满足上述条件,您必须缩短列或索引的定义长度,或继续使用 utf8mb3 而不是 utf8mb4。
以下是一些可能需要结构更改的示例
- 一个 - TINYTEXT列可以容纳最多 255 个字节,因此它可以容纳最多 85 个 3 字节或 63 个 4 字节字符。假设您有一个使用- utf8mb3的- TINYTEXT列,但必须能够包含超过 63 个字符。除非您还将数据类型更改为更长的类型(如- TEXT),否则您无法将其转换为- utf8mb4。- 同样,如果您想将其从 - utf8mb3转换为- utf8mb4,则可能需要将一个非常长的- VARCHAR列更改为一个更长的- TEXT类型。
- 对于使用 - COMPACT或- REDUNDANT行格式的表,- InnoDB的最大索引长度为 767 个字节,因此对于- utf8mb3或- utf8mb4列,您最多可以索引 255 个或 191 个字符,分别。如果您当前有索引长度超过 191 个字符的- utf8mb3列,则必须索引更少的字符。- 在使用 - COMPACT或- REDUNDANT行格式的- InnoDB表中,以下列和索引定义是合法的- col1 VARCHAR(500) CHARACTER SET utf8mb3, INDEX (col1(255))- 要改为使用 - utf8mb4,索引必须更小- col1 VARCHAR(500) CHARACTER SET utf8mb4, INDEX (col1(191))注意- 对于使用 - COMPRESSED或- DYNAMIC行格式的- InnoDB表,允许使用超过 767 字节(最多 3072 字节)的 索引键前缀。使用这些行格式创建的表允许您为- utf8mb3或- utf8mb4列分别索引最多 1024 或 768 个字符。有关相关信息,请参阅 第 17.21 节“InnoDB 限制” 和 DYNAMIC 行格式。
只有在您拥有非常长的列或索引时,才最有可能需要上述类型的更改。否则,您应该能够使用前面描述的 ALTER TABLE 将您的表从 utf8mb3 转换为 utf8mb4,而不会出现问题。
以下项目总结了其他潜在的不兼容性
- SET NAMES 'utf8mb4'会导致将 4 字节字符集用于连接字符集。只要没有从服务器发送 4 字节字符,就不应该出现问题。否则,预计每个字符最多接收三个字节的应用程序可能会遇到问题。相反,预计发送 4 字节字符的应用程序必须确保服务器能够理解它们。
- 对于复制,如果要在源上使用支持补充字符的字符集,则所有副本也必须理解它们。 - 此外,请记住以下一般原则:如果表在源和副本上具有不同的定义,这可能会导致意外结果。例如,最大索引键长度的差异使得在源上使用 - utf8mb3并在副本上使用- utf8mb4存在风险。
如果您已转换为 utf8mb4、utf16、utf16le 或 utf32,然后决定转换回 utf8mb3 或 ucs2(例如,降级到较旧版本的 MySQL),则以下注意事项适用
- utf8mb3和- ucs2数据应该不会出现问题。
- 服务器必须足够新才能识别引用您要从中转换的字符集的定义。 
- 对于引用 - utf8mb4字符集的对象定义,您可以在降级之前使用 mysqldump 转储它们,编辑转储文件以将- utf8mb4的实例更改为- utf8,然后在旧服务器中重新加载该文件,只要数据中没有 4 字节字符。旧服务器在转储文件对象定义中看到- utf8,并创建使用(3 字节)- utf8字符集的新对象。