求求你,别在 MySQL 中使用 UTF-8了!

📅 发布时间:2026/7/6 23:15:50 👁️ 浏览次数:
求求你,别在 MySQL 中使用 UTF-8了!
一、 为什么说别在 MySQL 中使用 UTF-8这个说法听起来有点耸人听闻但它精准地指出了 MySQL 长久以来存在的一个大问题MySQL 中的 utf8 实际上不是真正的 UTF-8 编码。1.1 utf8 vs. utf8mb4一字之差天壤之别MySQL 的 utf8 (别名 utf8mb3)这是一种专属编码它只支持每个字符最多3 个字节的 UTF-8 字符 。这意味着它只能编码 Unicode 中的基本多文种平面BMP的字符。真正的 UTF-8 编码标准的 UTF-8 编码是变长的每个字符使用 1 到4 个字节进行编码。MySQL 的 utf8mb4这才是真正的 UTF-8 编码支持每个字符最多4 个字节能够编码所有 Unicode 字符 。1.2 问题的根源一个无法挽回的历史错误为什么 MySQL 会犯这样的错误这要从历史说起。在 MySQL 最早开发时Unicode 还处于早期阶段当时的确没有需要 4 字节编码的字符。为了追求存储空间和性能的极致优化MySQL 的设计者们决定创造一种自己的utf8硬性限制为 3 字节 。然而随着 Unicode 的发展越来越多的生僻字、特殊符号以及如今无处不在的Emoji 表情符号如被纳入标准它们都需要 4 个字节进行存储。当用户尝试将这些字符插入到utf8编码的列中时MySQL 就会报错例如Incorrect string value: \xF0\x9F\x98\x82 for column name at row 1到了 2010 年MySQL 终于意识到这个问题的严重性但已经无法回头了。如果直接修改utf8的定义将会导致所有现有用户的数据损坏或需要重构数据库。因此他们选择了一个折中方案新推出一个名为 utf8mb4 的字符集来真正支持完整的 UTF-8 编码并让它作为真正的 UTF-8 标准。二、 我们应该怎么做全面拥抱 utf8mb4理解了问题的根源解决方案就非常清晰了所有还在使用 utf8 的用户都应该立即改用 utf8mb4。2.1 基础设置从源头抓起最好的方式是在一开始创建数据库和表时就指定正确的字符集。创建数据库时指定sqlCREATE DATABASE my_database CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;创建表时指定sqlCREATE TABLE my_table ( id INT PRIMARY KEY AUTO_INCREMENT, content TEXT ) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;2.2 如何选择正确的排序规则 (COLLATION)字符集之外排序规则也至关重要。针对utf8mb4常见的排序规则有以下几种utf8mb4_general_ci特点比较和排序速度快 。缺点对某些语言的排序规则支持不够精确比如德语、法语中的一些特殊字符排序可能不符合当地习惯。utf8mb4_unicode_ci特点基于标准的 Unicode 排序规则算法支持多语言排序结果更准确 。缺点相比general_ci性能会稍有损耗但在绝大多数场景下可以忽略不计。utf8mb4_0900_ai_ciMySQL 8.0 默认特点基于 Unicode 9.0 标准是unicode_ci的升级版提供了更准确的排序并且ai表示不区分重音Accent Insensitiveci表示不区分大小写Case Insensitive。建议如果你的 MySQL 版本是 8.0 或更高强烈推荐使用这个默认规则 。最佳实践建议如果不确定选哪个直接使用 MySQL 8.0 默认的utf8mb4_0900_ai_ci。如果你的版本较低5.5.3 以上推荐使用utf8mb4_unicode_ci在准确性和性能上取得了很好的平衡 。2.3 修改现有数据库、表和列如果你的项目已经存在需要将旧的utf8数据迁移到utf8mb4。修改数据库的默认字符集sqlALTER DATABASE database_name CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;注意这只会修改新表的默认字符集不会改变现有表和列。修改表和列的字符集推荐方法使用CONVERT TO CHARACTER SET可以一次性转换表和所有列的字符集 。sqlALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;⚠️ 警告对于大表这个操作可能会非常耗时并会对数据库造成较大压力建议在业务低峰期进行并提前做好备份 。2.4 配置文件和服务端的统一仅仅修改数据库还不够需要确保从客户端到服务端的整个链路字符集都是统一的 。编辑 MySQL 的配置文件Linux 通常是/etc/my.cnf或/etc/mysql/my.cnfWindows 是my.ini在对应区域添加或修改如下配置 ini[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 8.0 可以使用默认的 utf8mb4_0900_ai_ci # collation-server utf8mb4_0900_ai_ci # 可选但推荐防止客户端连接时覆盖服务端设置 skip-character-set-client-handshake修改完成后重启 MySQL 服务使配置生效 。2.5 应用层连接的设置最后应用程序在连接数据库时也需要指定使用utf8mb4字符集 。使用 SQL 命令连接后执行sqlSET NAMES utf8mb4;在 JDBC 连接 URL 中指定Java 应用确保 URL 中设置characterEncodingutf8mb4。并且可以移除旧的characterEncodingutf-8设置。textjdbc:mysql://localhost:3306/my_database?useUnicodetruecharacterEncodingutf8mb4serverTimezoneUTC在 Python MySQLdb/ PyMySQL中指定在建立连接时传入charsetutf8mb4参数 。三、 总结与展望MySQL 的 utf8 字符集是一个历史遗留的坑它并不是真正的 UTF-8。为了存储 Emoji 表情和生僻汉字确保数据的完整性和未来的兼容性必须使用 utf8mb4 字符集。