搜索全站
数据库 9 分钟阅读

WordPress 数据库字符集 utf8mb4 转换:完整步骤与乱码修复

MySQL 的 utf8 实际是 3 字节,存不了 emoji 和部分生僻字,必须转成 utf8mb4。本文讲清 utf8 与 utf8mb4 的区别、转换前的检查项、数据库与逐表转换的完整 SQL、索引长度问题的处理,以及转换后仍乱码的排查方向。

U
UFO_PF 2018-11-25 · 阅读 9 分钟
Wo 数据库
阅读提示
本文约 3,560 字,预计阅读 9 分钟。文中命令与配置均经过实测,可直接参考执行。

引言:内容里有个 emoji,文章就存不进去

典型症状:文章里带表情符号,保存时提示失败或直接截断;或者从别的系统导入数据后,中文变成 ??? 或 å­ 这类乱码。

第一个问题的根因是字符集:MySQL 的 utf8 只支持 3 字节,而 emoji 和部分汉字扩展区字符需要 4 字节,必须用 utf8mb4。第二个问题则多半是连接字符集与存储字符集不一致。

原理分析:三个字符集概念

概念 说明
字符集(charset) utf8(3 字节)、utf8mb4(4 字节)、latin1
排序规则(collation) 决定字符串比较与排序,如 utf8mb4_unicode_ci、utf8mb4_general_ci、utf8mb4_0900_ai_ci
连接字符集 客户端与服务端通信用的编码,由 wp-config.php 的 DB_CHARSET 决定

WordPress 默认的 DB_CHARSET 是 utf8mb4(自 4.2 起),DB_COLLATE 通常留空(跟随数据库默认)。

排序规则的选择:

  • utf8mb4_unicode_ci:按 Unicode 标准排序,准确性最好,稍慢;
  • utf8mb4_general_ci:快但排序规则简单(部分语言排序不准);
  • utf8mb4_0900_ai_ci:MySQL 8 默认,基于 UCA 9.0.0,MariaDB 不认识。

跨引擎迁移时统一用 utf8mb4_unicode_ci 最省心。

保姆级实操

第一步:检查当前状态

-- 库的字符集
SELECT SCHEMA_NAME, DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME
FROM information_schema.SCHEMATA WHERE SCHEMA_NAME='wordpress';

-- 各表的字符集
SELECT TABLE_NAME, TABLE_COLLATION
FROM information_schema.TABLES WHERE TABLE_SCHEMA='wordpress';

-- 各字段的字符集
SELECT TABLE_NAME, COLUMN_NAME, CHARACTER_SET_NAME, COLLATION_NAME
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA='wordpress' AND DATA_TYPE IN ('varchar','text','longtext','char');

用 WP-CLI:

wp db query "SELECT @@character_set_database, @@collation_database;"
wp config get DB_CHARSET

第二步:备份

mysqldump -u root -p --default-character-set=utf8mb4 --single-transaction wordpress > before-charset.sql

第三步:确认索引长度问题(关键)

utf8mb4 每个字符占 4 字节,InnoDB 单列索引上限 767 字节(老版本 innodb_large_prefix 关闭时)。如果你有 varchar(255) 且建了索引,转换后可能超限报错:

Specified key was too long; max key length is 767 bytes

解法一(MySQL 5.7.7+ 默认支持 3072 字节):确认参数

innodb_large_prefix = ON
innodb_file_format = Barracuda
innodb_file_per_table = ON

解法二:把字段缩短,如 varchar(255) 改 varchar(191)。

第四步:转换数据库

ALTER DATABASE wordpress CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

这只影响新建表的默认值,已有表需要单独转。

第五步:逐表转换(生成语句)

SELECT CONCAT('ALTER TABLE `', TABLE_NAME, '` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;')
FROM information_schema.TABLES
WHERE TABLE_SCHEMA='wordpress' AND TABLE_TYPE='BASE TABLE';

把输出的语句批量执行。CONVERT TO 会同时转换表内所有字符字段,比逐个字段改方便。

WP-CLI 方式:

wp db query "ALTER TABLE wp_posts CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"

或者用插件/脚本批量:

for t in $(wp db query "SHOW TABLES" --skip-column-names); do
  wp db query "ALTER TABLE $t CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
done

第六步:确认 wp-config.php

define('DB_CHARSET', 'utf8mb4');
define('DB_COLLATE', '');

DB_COLLATE 留空表示跟随数据库默认。若明确指定,必须与数据库实际排序规则一致,否则可能出现 Illegal mix of collations。

第七步:修复”双重编码”乱码

如果转换后中文仍显示为 å­ 之类,说明是双重编码(原本 utf8 的数据被当成 latin1 存了一遍)。修复方式:

-- 先转回 latin1 的二进制视角,再转 utf8mb4
ALTER TABLE wp_posts MODIFY post_content LONGTEXT CHARACTER SET latin1;
ALTER TABLE wp_posts MODIFY post_content LONGBLOB;
ALTER TABLE wp_posts MODIFY post_content LONGTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

操作前必须备份,且先在单表上试。

第八步:验证

UPDATE wp_posts SET post_title='测试 emoji ????' WHERE ID=1;
SELECT post_title, HEX(post_title) FROM wp_posts WHERE ID=1;

能正常存读 emoji 即成功。

常见踩坑与失败案例

  1. 只改了库没改表 —— 新建表是新字符集,老表还是 utf8,混合状态最麻烦。
  2. Illegal mix of collations —— 表之间排序规则不一致,JOIN 时报错。统一成一种。
  3. 案例:某站从 MySQL 5.6(utf8)迁到 MySQL 8(utf8mb4_0900_ai_ci)后,一个多语言插件的排序报错。最后把所有表统一成 utf8mb4_unicode_ci 解决。
  4. 索引超长导致转换失败 —— 大表转换耗时长且可能中断。建议在低峰期操作,先用小表验证流程。
  5. 改了 DB_CHARSET 但没转数据 —— 连接用 utf8mb4 而存储是 utf8,写入时反而更容易出错。

总结

字符集问题的处理顺序是:先备份 → 检查现状 → 确认索引长度 → 转库 → 逐表 CONVERT TO → 核对 wp-config.php → 验证 emoji。排序规则我建议统一用 utf8mb4_unicode_ci,它在 MySQL 与 MariaDB 之间都能用,避免跨引擎迁移的坑。至于已经出现的双重编码乱码,要在备份基础上用”latin1 → blob → utf8mb4″三步法修复,且务必先拿单表试,确认效果再全量执行。

U
UFO_PF作者

专注 WordPress 生态的实战作者,内容以「可复制、可验证」为第一原则。

留下你的想法

邮箱地址不会被公开。带 * 的为必填项。