MySQL的utf8编码之谜

本文由 ChatMoney团队出品

之前,在将emoji表情😲😳存入MySQL时,我遇到了一个棘手的问题——数据无法导入。经过一番摸索,我将数据库编码从utf8更改为utf8mb4,问题得以解决。当时并未深究其背后的原因。

时光荏苒,一年后,我偶然读到一篇文章,提到emoji字符占用4个字节,通常需要使用utf-8编码接收,否则可能会出现错误。这让我回想起去年更改MySQL编码的经历,心中不禁产生疑问:MySQL的utf8编码难道不是真正的UTF-8编码吗?

带着这个疑问,我查阅了大量资料,发现这竟然是MySQL的一个历史遗留问题。没想到,如此强大的MySQL也有这段鲜为人知的往事。

一、回顾报错经历

当我尝试将包含emoji的文本直接写入SQL执行insert语句时,出现了以下错误:

INSERT INTO `csjdemo`.`student` (`ID`, `NAME`, `SEX`, `AGE`, `CLASS`, `GRADE`, `HOBBY`)
VALUES ('20', '陈哈哈😓', '男', '20', '181班', '9年级', '看片儿');
[Err] 1366 - Incorrect string value: '\xF0\x9F\x98\x93' for column 'NAME' at row 1

在将数据库编码、系统编码以及表字段的编码格式更改为utf8mb4后,问题得到了解决:

INSERT INTO `student` (`ID`, `NAME`, `SEX`, `AGE`, `CLASS`, `GRADE`, `HOBBY`)
VALUES (null, '陈哈哈😓😓', '男', '20', '181班', '9年级', '看片儿');

二、揭秘MySQL中utf8的趣事

原来,MySQL的“utf8”并非真正的UTF-8。在MySQL中,“utf8”编码每个字符最多支持三个字节,而真正的UTF-8每个字符最多支持四个字节。

在utf8编码中,中文占用3个字节,数字、英文、符号占用1个字节。而emoji符号和部分复杂文字、繁体字则占用4个字节,导致写入失败。因此,应将编码更改为utf8mb4。

令人惊讶的是,MySQL并未修复这个bug,而是在2010年发布了一个名为“utf8mb4”的字符集,巧妙地绕过了这个问题。尽管如此,他们并未广泛宣传这个新字符集,或许是因为这个bug让他们感到尴尬。因此,网络上仍有许多建议开发者使用“utf8”的误导性信息。

  1. utf8mb4:真正的UTF-8

MySQL的“utf8mb4”才是真正的“UTF-8”。MySQL的“utf8”实际上是一种“专属编码”,它能编码的Unicode字符非常有限。

在此提醒:所有使用“utf8”的MySQL和MariaDB用户都应改用“utf8mb4”,永远不要再使用“utf8”。

那么,什么是编码?什么是UTF-8?

计算机使用0和1存储文本,例如字符“C”被存为“01000011”。计算机在显示字符时需要经过两个步骤:将0和1转换为数字,再在Unicode字符集中查找对应的字符。

几乎所有的网络应用都使用Unicode字符集,因为它包含了上百万个字符。UTF-8编码可以节省空间,字符“C”只需8位,而“😓”这样的字符则需要32位。

  1. utf8的简史

为何MySQL开发者会让“utf8”失效?或许可以从MySQL版本提交日志中寻找答案。

MySQL从4.1版本开始支持UTF-8,即2003年。当时使用的UTF-8标准(RFC 2279)最多支持每个字符6个字节。然而,2002年3月28日,MySQL开发者在一个预览版中使用了这个标准。同年9月,他们对MySQL源代码进行了调整,使得“UTF8”最多只支持3个字节的序列。

这个变更的原因不得而知,但在迁移到Git后,许多提交者的名字丢失了。2003年9月的邮件列表中也找不到解释这一变更的线索。

我们猜测,MySQL开发者原本想帮助用户在空间和速度上取得双赢,但最终却导致了“utf8”编码的问题。因此,没有赢家。那些希望双赢的用户在使用“utf8”的CHAR列时,实际上占用的空间更大,速度也更慢。而追求正确性的用户,在使用“utf8”编码时,却无法保存4个字节的字符。

这个不合法的字符集发布后,MySQL无法修复它,因为这需要所有用户重新构建数据库。最终,MySQL在2010年发布了“utf8mb4”来支持真正的UTF-8。

关于我们

本文由ChatMoney团队出品,ChatMoney专注于AI应用落地与变现,我们提供全套、持续更新的AI源码系统与可执行的变现方案,致力于帮助更多人利用AI来变现,欢迎进入ChatMoney获取更多AI变现方案!

  • 17
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值