一、
为什么说"别在

UTF-8"?
这个说法听起来有点耸人听闻,但它精准地指出了
MySQL
长久以来存在的一个大问题:MySQL
"utf8"
"utf8mb4":一字之差,天壤之别
MySQL
"utf8"
utf8mb3):这是一种"专属编码",它只支持每个字符最多3
UTF-8
中的基本多文种平面(BMP)的字符。
真正的
UTF-8
个字节进行编码。
MySQL
"utf8mb4":这才是真正的
UTF-8
问题的根源:一个无法挽回的历史错误
为什么
MySQL
字节编码的字符。
为了追求存储空间和性能的极致优化,MySQL
的设计者们决定创造一种自己的"utf8",硬性限制为
Unicode
的发展,越来越多的生僻字、特殊符号以及如今无处不在的Emoji
表情符号(如
😂👍🏻)被纳入标准,它们都需要个字节进行存储。
当用户尝试将这些字符插入到"utf8"编码的列中时,MySQL
/>
Incorrect终于意识到这个问题的严重性,但已经无法回头了。
如果直接修改"utf8"的定义,将会导致所有现有用户的数据损坏或需要重构数据库。
因此,他们选择了一个折中方案:新推出一个名为
"utf8mb4"
utf8mb4
理解了问题的根源,解决方案就非常清晰了:所有还在使用
"utf8"
"utf8mb4"。
2.1
基础设置:从源头抓起
最好的方式是在一开始创建数据库和表时就指定正确的字符集。
创建数据库时指定:
sql
CREATE
DATABASE
utf8mb4_unicode_ci;
创建表时指定:
sql
CREATE
TABLE
utf8mb4_unicode_ci;
2.2
(COLLATION)
字符集之外,排序规则也至关重要。
针对
utf8mb4,常见的排序规则有以下几种:utf8mb4_general_ci:特点:比较和排序速度快
。
缺点:对某些语言的排序规则支持不够精确,比如德语、法语中的一些特殊字符排序可能不符合当地习惯。
utf8mb4_unicode_ci:特点:基于标准的
Unicode
排序规则算法,支持多语言,排序结果更准确
。
缺点:相比
general_ci,性能会稍有损耗,但在绝大多数场景下可以忽略不计。
utf8mb4_0900_ai_ci(MySQL8.0+
默认):
特点:基于
Unicode
标准,是
unicode_ci的升级版,提供了更准确的排序,并且ai表示不区分重音(AccentInsensitive),
ci表示不区分大小写(CaseInsensitive)。
建议:如果你的
MySQL
。
最佳实践建议:如果不确定选哪个,直接使用
MySQL
默认的
utf8mb4_0900_ai_ci。如果你的版本较低(5.5.3
以上),推荐使用
utf8mb4_unicode_ci,在准确性和性能上取得了很好的平衡修改现有数据库、表和列
如果你的项目已经存在,需要将旧的
utf8数据迁移到utf8mb4。修改数据库的默认字符集:
sql
ALTER
DATABASE
utf8mb4_unicode_ci;
注意:这只会修改新表的默认字符集,不会改变现有表和列。
修改表和列的字符集(推荐方法):
/>使用
CONVERTutf8mb4_unicode_ci;
⚠️
警告:对于大表,这个操作可能会非常耗时,并会对数据库造成较大压力,建议在业务低峰期进行,并提前做好备份
配置文件和服务端的统一
仅仅修改数据库还不够,需要确保从客户端到服务端的整个链路字符集都是统一的
MySQL
通常是
/etc/my.cnf或/etc/mysql/my.cnf,Windows是
my.ini),在对应区域添加或修改如下配置:
ini
[client]
=
可选,但推荐:防止客户端连接时覆盖服务端设置
skip-character-set-client-handshake
修改完成后,重启
MySQL
应用层连接的设置
最后,应用程序在连接数据库时,也需要指定使用
utf8mb4字符集SQL
命令(连接后执行):
sql
SET
NAMES
'utf8mb4';
在
JDBC
中设置
characterEncoding=utf8mb4。并且可以移除旧的
characterEncoding=utf-8设置。text
jdbc:mysql://localhost:3306/my_database?useUnicode=true&characterEncoding=utf8mb4&serverTimezone=UTC
在
Python
PyMySQL)中指定:
/>在建立连接时,传入
charset="utf8mb4"参数总结与展望
MySQL
字符集是一个历史遗留的"坑",它并不是真正的
Emoji
表情和生僻汉字,确保数据的完整性和未来的兼容性,必须使用
"utf8mb4"


