WPML

什么是 MySQL 中的字符集和排序规则

当 WordPress 在数据库中存储您网站的内容(如文章、标题、已翻译的字符串等)时,它会使用字符集(character set)来表示字符,并使用排序规则(collation)来定义如何比较和排序这些字符。

字符集(Charset)
定义字符在数据库中的存储方式——本质上就是哪些字节代表哪些字符。
排序规则(Collation)
定义比较这些字符的规则(例如,是否区分大小写、是否区分重音以及排序顺序)。

为什么这对多语言网站很重要

WPML 支持多语言内容,其中通常包括:

  • 特殊字符(如 ñ、é、ö)
  • 非拉丁文字(如阿拉伯语、日语、中文、希伯来语)
  • 表情符号和符号(🎉、✔️ 等)

其中许多字符需要超过 3 个字节才能正确存储。如果您的数据库使用不兼容的排序规则,字符可能会丢失、被替换为 �,或者引发数据库错误(例如“Incorrect string value”)。

这就是为什么我们强烈建议使用支持 4 字节 Unicode 字符的排序规则。

我们的建议

使用 utf8mb4 字符集兼容 Unicode 的排序规则,例如:

  • utf8mb4_unicode_ci – 兼容性广,是不错的默认选择
  • utf8mb4_unicode_520_ci – 在 MySQL 5.6+ 上具有更好的 Unicode 处理能力
  • utf8mb4_general_ci – 速度稍快,但 Unicode 比较不够准确
  • utf8mb4_bin – 区分大小写和重音(二进制比较)

这些都可以与 WPML 安全配合使用。


重要提示:MySQL 中旧的 utf8 字符集每个字符最多仅支持 3 个字节。它无法处理某些字符(如表情符号或某些表意文字)。请避免将其用于多语言内容。

MySQL 的默认设置是什么

MySQL 版本默认字符集默认排序规则兼容 Unicode
< 5.5latin1latin1_swedish_ci
5.5.xutf8utf8_general_ci
5.7+utf8mb4utf8mb4_general_ci / utf8mb4_unicode_ci
8.0+utf8mb4utf8mb4_0900_ai_ci

WordPress 可能并不总是遵循 MySQL 的默认设置——它可以通过配置或迁移来覆盖默认设置。

为新网站设置字符集和排序规则

为确保 WordPress 使用正确的字符集和排序规则创建新表,请在您的 wp-config.php 中定义以下内容:

define( 'DB_CHARSET', 'utf8mb4' ); // If you have utf8 that's fine, WP will automatically map it as utf8mb4
define( 'DB_COLLATE', 'utf8mb4_unicode_ci' );

这将应用于新安装的网站和新创建的表。

检查现有网站和表的字符集和排序规则

下面介绍了如何检查现有网站上的字符集和排序规则。

选项 1 phpMyAdmin

  1. 前往您网站的数据库。
  2. 检查每个表旁边的“Collation”(排序规则)列。
  3. 单击一个表,查看每一列各自的排序规则。

选项 2 WP-CLI

bash

wp db query "SELECT TABLE_NAME, TABLE_COLLATION FROM information_schema.tables WHERE table_schema = 'your_db_name';"

您还可以检查单个列:

bash

wp db query "SHOW FULL COLUMNS FROM wp_posts;"

如果您看到排序规则以 utf8mb4_ 开头,则说明它已准备好支持所有类型的 Unicode 和 4 字节表意文字。字符集也没有问题。

如果您看到其他内容(例如 utf8_*),则需要对其进行更改。

请注意,每一列的排序规则可能有所不同。

更新现有表和列的字符集和排序规则

wp-config.php 文件中更新 DB_CHARSET 和 DB_COLLATE 常量只会影响新表。要将更改应用于现有表和列,您必须使用 SQL 手动转换它们。

我们还建议使用以下命令更新数据库的默认 MySQL 排序规则:

ALTER DATABASE your_database_name CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

务必先进行备份

在运行任何转换查询之前:

  • 使用 phpMyAdmin 或 mysqldump 导出您的数据库
  • 妥善保存,以防出现问题

警告:在严格模式下更新排序规则可能会失败

在更新整个表(或数据库)的排序规则时,MySQL 可能会重建表并重新验证所有列的默认值——包括 DATETIME 等不相关的列。如果您的数据库在严格的 SQL 模式(STRICT_TRANS_TABLES、NO_ZERO_DATE)下运行,具有默认值(如 ‘0000-00-00 00:00:00’)的列将引发错误,例如:

#1067 - Invalid default value.

什么是严格模式

严格模式控制 MySQL 在向数据库中添加或更新数据时如何处理无效或缺失的值。值可能因多种原因而无效。例如,它的数据类型可能与列不匹配,或者可能超出范围。

您可以在 MySQL 文档中找到有关严格模式下不同类型数据验证的信息。

严格模式如何影响 WordPress 网站数据库

默认情况下,WordPress 将 ‘0000-00-00 00:00:00’ 用作某些 datetime 列的默认值,而 NO_ZERO_DATE 严格模式不接受这一值。

请注意,这些默认值在最初创建表时(例如在 WordPress 设置期间)是允许的,但在严格环境下的 ALTER 操作中会失败。

如何检查是否启用了严格模式

运行以下命令:

SELECT @@SESSION.sql_mode, @@GLOBAL.sql_mode;

查找:

  • STRICT_TRANS_TABLES
  • STRICT_ALL_TABLES
  • NO_ZERO_DATE

如果您找到其中任何一项,则说明启用了严格模式。

为避免在更新字符集和排序规则期间出现错误,您只需禁用 NO_ZERO_DATE 严格模式。

如何安全地继续操作

执行以下操作之一以安全地继续:

1. 除非确实需要更改排序规则,否则请避免更改列和表。

2. 在运行转换查询时,仅针对当前会话临时禁用严格模式。您可以使用以下命令执行此操作:

SET SESSION sql_mode = REPLACE(@@sql_mode, 'NO_ZERO_DATE', '');

注意:MySQL 未来计划合并严格模式。

如果出现特定于您数据的其他问题,您可能需要使用以下命令禁用任何严格模式:

SET SESSION sql_mode = '';

用于转换数据的查询

转换整个数据库

以下命令将为您数据库中的每个表生成一个 ALTER TABLE 查询:

SELECT CONCAT(
  'ALTER TABLE `', TABLE_NAME, '` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;'
) AS query
  FROM INFORMATION_SCHEMA.TABLES
  WHERE TABLE_SCHEMA = 'your_database_name';

在 phpMyAdmin 中运行生成的查询,或者将其复制粘贴到 MySQL CLI / WP-CLI 中。

这可确保您数据库中的所有表都采用新的字符集和排序规则。

转换特定表 可选/辅助
ALTER TABLE wp_posts 
  CONVERT TO CHARACTER SET utf8mb4 
  COLLATE utf8mb4_unicode_ci;

这将更新 wp_posts 表中的所有文本列,以使用 utf8mb4 和指定的排序规则。


转换特定列 可选/辅助
ALTER TABLE wp_posts 
  CHANGE post_title post_title TEXT 
  CHARACTER SET utf8mb4 
  COLLATE utf8mb4_unicode_ci;

注意:

  • 您必须在 CHANGE 中完全重新声明该列(类型、名称)。
  • 确保列类型与现有类型匹配。

转换时的常见错误

以下是您在转换表和列时可能会遇到的两个常见错误。

字符集和排序规则不匹配
-- INVALID: utf8 collation with utf8mb4 charset
ALTER TABLE wp_posts CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8_general_ci;
-- Error: COLLATION 'utf8_general_ci' is not valid for CHARACTER SET 'utf8mb4'

解决方案:

  • 使用匹配的排序规则:utf8mb4_*

索引键长度限制
ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes

在某些配置中(特别是低于 5.7 的 MySQL 版本),当每个字符增加一个字节时,可能会超出最大索引键长度。

解决方案:

  • 如果需要,将编入索引的 VARCHAR(255) 缩短为 VARCHAR(191)
  • 或者升级到 MySQL 5.7+ 并确保启用 innodb_large_prefix

总结

  • 使用 utf8mb4 字符集以获得全面的 Unicode 支持
  • 使用兼容的排序规则:utf8mb4_unicode_ciutf8mb4_0900_ai_ci
  • 更新 wp-config.php 以用于新表
  • 运行 SQL 迁移以修复现有表
  • 切勿混合使用字符集和排序规则——MySQL 会拒绝或破坏它们。