MySQL 从 utf8 切换到 utf8mb4
utf8mb4
幸运的是,MySQL 5.5.3(2010 年初发布)引入了一种名为 utf8mb4
的新编码,它映射到正确的 UTF-8,因此完全支持 Unicode,包括星体符号。
第一步:创建备份
在要升级的服务器上创建所有数据库的备份。 安全第一!
第二步:升级MySQL服务器
将 MySQL 服务器升级到 v5.5.3+,或请服务器管理员为你完成。
第三步:修改数据库、表和列
更改数据库、表和列的字符集和排序规则属性以使用 utf8mb4
而不是 utf8
。
# For each database:
ALTER DATABASE database_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
# For each table:
ALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
# For each column:
ALTER TABLE table_name CHANGE column_name column_name VARCHAR(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
# (Don’t blindly copy-paste this! The exact statement depends on the column type, maximum length, and other properties. The above line is just an example for a `VARCHAR` column.)
由于 utf8mb4
与 utf8
完全向后兼容,因此不应发生 mojibake 或其他形式的数据丢失。 (但你有备份,对吧?)
第四步:检查列和索引键的最大长度
这可能是整个升级过程中最乏味的部分。
从 utf8
转换为 utf8mb4
时,列或索引键的最大长度以字节为单位不变。 因此,它在字符方面更小,因为字符的最大长度现在是四个字节而不是三个。
例如,一个 TINYTEXT
列最多可以容纳 255 个字节,这对应于 85 个三字节字符或 63 个四字节字符。 假设我们有一个使用 utf8 的 TINYTEXT
列,但必须能够包含超过 63 个字符。 鉴于此要求,我们不能将此列转换为 utf8mb4,除非我们还将数据类型更改为更长的类型,例如 TEXT
— 因为如果我们尝试用四字节字符填充它,将只能 输入 63 个字符,但不能更多。
索引键也是如此。 InnoDB
存储引擎的最大索引长度为 767 字节,因此对于 utf8 或 utf8mb4 列,我们最多可以分别索引 255 或 191 个字符。 如果我们当前的 utf8 列的索引长度超过 191 个字符,则在使用 utf8mb4 时需要索引较少的字符。 (因此,我不得不将一些索引 VARCHAR(255)
列更改为 VARCHAR(191)
。)
第五步:修改连接、客户端和服务器字符集
在我们的应用程序代码中,将连接字符集设置为 utf8mb4。 这可以通过简单地将 SET NAMES utf8
的任何变体替换为 SET NAMES utf8mb4
来完成。 如果我们的旧 SET NAMES
语句指定了排序规则,请确保也更改它,例如 SET NAMES utf8 COLLATE utf8_unicode_ci
变成 SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci
。
确保同时设置客户端和服务器字符集。 我的 MySQL 配置文件 (/etc/my.cnf) 中有以下内容:
[client]
default-character-set = utf8mb4
[mysql]
default-character-set = utf8mb4
[mysqld]
character-set-client-handshake = FALSE
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
我们可以轻松确认这些设置是否正常工作:
mysql> SHOW VARIABLES WHERE Variable_name LIKE 'character\_set\_%' OR Variable_name LIKE 'collation%';
+--------------------------+--------------------+
| Variable_name | Value |
+--------------------------+--------------------+
| character_set_client | utf8mb4 |
| character_set_connection | utf8mb4 |
| character_set_database | utf8mb4 |
| character_set_filesystem | binary |
| character_set_results | utf8mb4 |
| character_set_server | utf8mb4 |
| character_set_system | utf8 |
| collation_connection | utf8mb4_unicode_ci |
| collation_database | utf8mb4_unicode_ci |
| collation_server | utf8mb4_unicode_ci |
+--------------------------+--------------------+
10 rows in set (0.00 sec)
如我们所见,所有相关选项都设置为 utf8mb4,除了 character_set_filesystem
应该是二进制的,除非我们使用的文件系统支持文件名中的多字节 UTF-8 编码字符,而 character_set_system
始终是 utf8 并且不能被覆盖。
注意
:默认字符集和排序规则也可以在其他一些级别进行配置。
第六步:修复和优化所有表
升级 MySQL 服务器并进行上述必要更改后,确保修复和优化所有数据库和表。 升级后我没有立即执行此操作(我认为没有必要,因为乍一看似乎一切正常),并且遇到了一些奇怪的错误,其中 UPDATE
语句没有任何效果,即使没有 错误被抛出。
我们可以为每个要修复和优化的表运行以下 MySQL 查询:
# For each table
REPAIR TABLE table_name;
OPTIMIZE TABLE table_name;
幸运的是,这可以使用命令行 mysqlcheck
实用程序轻松一次性完成:
$ mysqlcheck -u root -p --auto-repair --optimize --all-databases
这将提示输入 root 用户的密码,之后将修复和优化所有数据库中的所有表。
总结
永远不要在 MySQL 中使用 utf8——总是使用 utf8mb4。 更新数据库和代码可能需要一些时间,但绝对值得付出努力。 为什么要任意限制可以在数据库中使用的符号集? 为什么每次用户输入星体符号作为评论或消息的一部分或我们存储在数据库中的任何内容时,都会丢失数据? 没有理由不在所有地方争取完全的 Unicode
支持。 做正确的事,使用 utf8mb4。 🍻
相关文章
使用 Mysqldump 备份 MySQL 中的数据
发布时间:2023/05/09 浏览次数:192 分类:MySQL
-
本篇文章将介绍如何使用 mysqldump 只备份数据。 在这里,我们将探讨 --no-create-info 、--compact 、--skip-triggers 和 --no-create-db 选项。
更新 MySQL 表中的主键
发布时间:2023/05/09 浏览次数:61 分类:MySQL
-
本篇文章介绍如何更新 MySQL 表中的主键。 我们将使用 ALTER 命令对主键进行任何更改。更新 MySQL 表中的主键 我们可以在多种情况下更新 MySQL 表中的主键。
在 MySQL 中获取命令历史记录
发布时间:2023/05/09 浏览次数:150 分类:MySQL
-
本文重点介绍了在 Windows 和 Linux 中获取我们已执行的 MySQL 命令历史记录的各种方法。MySQL命令历史
Oracle 的 decode 函数在 MySQL 中的等价物
发布时间:2023/05/09 浏览次数:115 分类:MySQL
-
本篇文章介绍了三种替代实现,我们可以将它们用作 MySQL 中 Oracle 的 decode() 函数的等价物。 为此,我们将使用 IF()、CASE 以及 FIELD() 和 ELT() 的组合。
使用 Ubuntu 连接远程 MySQL 服务器的不同方法
发布时间:2023/05/09 浏览次数:97 分类:MySQL
-
在本文中我们将学习如何使用 Ubuntu 连接远程 MySQL 服务器来操作数据以及启动和停止 MySQL 服务器。
在 Linux 中安装 MySQL 客户端
发布时间:2023/05/09 浏览次数:72 分类:MySQL
-
在 Linux 中安装 MySQL 客户端的命令。Linux 和 Unix 等环境作为命令行界面工作,仅在命令的帮助下运行。
在 MySQL 中转换为十进制
发布时间:2023/05/09 浏览次数:150 分类:MySQL
-
有时,我们可能需要将一种数据类型转换为另一种数据类型。 下面是我们如何使用带有 DECIMAL(M,D) 的 CAST() 和 CONVERT() 函数在 MySQL 中转换为十进制。
在 MySQL 中获取当前日期和时间
发布时间:2023/05/09 浏览次数:145 分类:MySQL
-
本篇文章我们将学习 NOW()、CURRENT_TIMESTAMP()(也写为 CURRENT_TIMESTAMP)和 SYSDATE() 来获取 MySQL 中的当前日期和时间。 我们还将看到这三个功能之间的比较。在 MySQL 中获取当前日期和时间
更改 MySQL 服务器中的 max_allowed_packet Size
发布时间:2023/05/09 浏览次数:142 分类:MySQL
-
本篇文章介绍如何更改 MySQL 服务器中的 max_allowed_packet 大小。 为了了解这一点,我们将使用两个操作系统,Windows 10 和 Linux (Ubuntu)。