我的编程空间,编程开发者的网络收藏夹
学习永远不晚

永远不要在 MySQL 中使用 utf8,使用 utf8mb4 作为代替

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

永远不要在 MySQL 中使用 utf8,使用 utf8mb4 作为代替

今天的错误:我试图在 MariaDB 「utf8」 编码的数据库中存储一个 UTF-8 字符串,Rails 出现了一个奇怪的错误:

Incorrect string value: ‘\xF0\x9F\x98\x83 <…’ for column ‘summary’ at row 1

这是一个 UTF-8 客户端和一个 UTF-8 服务器,位于具有 UTF-8 排序规则的 UTF-8 数据库中。 字符串「? <…」是有效的 UTF-8。

但问题是:MySQL 的「utf8不是 UTF-8

「utf8」编码仅支持每个字符三个字节。 真正的 UTF-8 编码——包括你在内的每个人都在使用——每个字符最多需要四个字节。

MySQL 开发人员从未修复过这个错误。 他们在 2010 中发布了一个解决方法:一个名为「utf8mb4」的新字符集。

当然,他们从来没有宣传过这个(可能是因为这个错误太尴尬了)。 现在,网络上的指南建议用户使用「utf8」。 所有这些指南都是错误的。

简而言之:

  • MySQL「utf8mb4」表示「UTF8」。

  • MySQL「utf8」表示「专有字符编码」。 这种编码不能编码许多 Unicode 字符。

我将在这里做一个全面的声明:所有 当前使用「utf8」的 MySQL 和 MariaDB 用户应该 实际上 使用「utf8mb4」。 没有人应该使用「utf8」。

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

Joel on Software 写了我最喜欢的介绍, 我来简述它。

计算机将文本存储为 1 和 0。 本段中的第一个字母存储为「01000011」,计算机绘制了「C」。 计算机分两步选择了「C」:

  1. 计算机读取「01000011」并确定它是数字 67。这是因为 67 被编码为「01000011」。

  2. 你的计算机在 Unicode字符集 中查找字符编号 67,发现 67 表示「C」。

当我输入「C」时,同样的事情发生在我身上:

  1. 我的电脑将「C」映射到 Unicode 字符集中的 67。

  2. 我的电脑 编码 67,将「01000011」发送到此 Web 服务器。

字符集 是一个已解决的问题。 互联网上几乎每个程序都使用 Unicode 字符集,因为没有动机使用另一个字符集。

编码 更像是一种判断。 Unicode 有超过一百万个字符的插槽。 (「C」和「?」就是两个这样的字符。)最简单的编码 UTF-32 使每个字符占用 32 位。 这很简单,因为计算机多年来一直将 32 位组视为数字,而且它们真的很擅长。 但它没有用:这是浪费空间。

UTF-8 节省空间。 在 UTF-8 中,像「C」这样的常见字符占用 8 位,而像「?」这样的稀有字符占用 32 位。 其他字符占用 16 或 24 位。 像这样的博客文章在 UTF-8 中占用的空间大约是 UTF-32 中的四倍。 所以它的加载速度快了四倍。

你可能没有意识到,但我们的计算机在幕后同意使用 UTF-8。 如果他们没有,那么当我输入「?」时,你会看到一堆乱七八糟的随机数据。

MySQL 「utf8」 字符集与其他程序不一致。 当他们说「?」时,它就开始了。

一点 MySQL 历史

为什么 MySQL 开发人员让「utf8」无效? 我们可以通过查看提交日志来猜测。

MySQL 支持 UTF-8,因为 version 4.1

那是 2003 年——在今天的 UTF-8 标准之前,RFC 3629.

之前的 UTF-8 标准 RFC 2279 支持每个字符最多六个字节。 MySQL 开发人员于 2002 年 3 月 28 日在 [MySQL 4.1 的第一个预发布版本] (github.com/mysql/mysql-server/comm...) 中编写了 RFC 2279。

然后在 9 月对 MySQL 的源代码进行了一个神秘的单字节调整:「UTF8 现在最多可处理 3 字节序列。」

谁要求这个改变? 为什么? 我不知道。 2003 年 9 月左右的邮件列表中没有任何内容可以解释这一变化。 (RFC 2279 在 2003 年 11 月被宣布过时,为当前的 UTF-8 标准让路,RFC 3629。)

但我可以猜到为什么 MySQL 违反了标准。

早在 2002 年,如果用户可以保证表中的每一行都具有相同的内容,MySQL 就为用户提供了 速度提升 字节数。 为此,用户将文本列声明为「CHAR」。 「CHAR」列中的每条记录的值都具有相同数量的字符。 如果输入的字符太少,MySQL 会在末尾添加空格; 如果输入太多字符,MySQL 会截断最后一个字符。

当 MySQL 开发人员第一次尝试 UTF-8 时,其过去每个字符 6 个字节,他们可能会犹豫:一个 CHAR(1) 列需要 6 个字节; CHAR(2) 列将占用 12 个字节; 等等。

让我们明确一点:从未发布过的最初行为是正确的。 它有据可查并被广泛采用,任何了解 UTF-8 的人都会同意它是正确的。

但很明显,一个 MySQL 开发人员(或用户,或客户)担心他们会做两件事:

  1. 选择 CHAR 列。(CHAR 格式现在是一个遗物。当时,MySQL 使用 CHAR 列更快。从 2005 年开始,它就不是了。)

  2. 选择将这些 CHAR 列编码为「utf8」。

我的猜测是 MySQL 开发人员打破了他们的「utf8」编码来帮助这些用户:1)试图优化空间和速度的用户;
2) 忽略了对速度和空间的优化。

没有人是赢家。 想要速度和空间的用户仍然 错误地使用 「utf8」CHAR 字段,因为这些字段仍然比它们应有的更大和更慢。 而原本想要正确性的开发者使用「utf8」是错误的,因为它不能存储「?」。

一旦 Mysql 发布了这个无效的字符集,它就永远无法修复它:这将迫使每个用户重建数据库。MySQL 最终在 2010 ,发布了 UTF-8 的支持,有一个不同的名字:「utf8mb4」。

为何如此令人沮丧

显然这周我很沮丧。我的错误很难被找到,因为我被「uft8」这个名字所迷惑了。而且我并不是唯一一个,几乎我在网上找到的文章都将「uft8」吹捧为「UTF-8」。

「utf8」总是错误的。 它是一个专有的字符串集。它创造了新的问题,而且并没有解决它本来想要解决的问题。

我的总结

  1. 数据库系统有微妙的错误和怪异,你可以通过避免使用数据库系统来避免很多错误。

  2. 如果你需要一个数据库,请不要使用「MySQL」或者「MariaDB」。请使用 「 Postgresql 」。

  3. 如果你需要使用 「MySQL」或者「MariaDB」,千万不要使用「UTF-8」,当你想要用「UTF-8」的时候,总是使用「utf8mb4」,现在就 转换你的数据库 从而避免之后的麻烦。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

永远不要在 MySQL 中使用 utf8,使用 utf8mb4 作为代替

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

永远不要在 MySQL 中使用 utf8,使用 utf8mb4 作为代替

今天的错误:我试图在 MariaDB 「utf8」 编码的数据库中存储一个 UTF-8 字符串,Rails 出现了一个奇怪的错误:Incorrectstringva
2022-11-16

为什么永远不要在MySQL中使用UTF-8

这篇文章给大家介绍为什么永远不要在MySQL中使用UTF-8,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。最近我遇到了一个bug,我试着通过Rails在以“utf8”编码的MariaDB中保存一个UTF-8字符串,然后
2023-06-19

User这个词为什么不要在代码中使用

今天给大家介绍一下User这个词为什么不要在代码中使用。文章的内容小编觉得不错,现在给大家分享一下,觉得有需要的朋友可以了解一下,希望对大家有所帮助,下面跟着小编的思路一起来阅读吧。当你意识到你在项目开始时做的轻量、简单的设想竟然完全错了时
2023-06-28

编程热搜

目录