应用MYSQL的时间经常会碰着一个问题,试着经由过程 Rails 在以“utf8”编码的 MariaDB 中留存一个 UTF-8 字符串,然后泛起了一个希奇新奇的毛病:
Incorrect string value: ‘\xF0\x9F\x98\x83 <…’ for column ‘summary’ at row 1
UTF-8 编码的客户端,办事器也是 UTF-8 编码的,数据库也是,就连要留存的这个字符串“ <…”也是正当的 UTF-8。问题的症结在于,MySQL 的“utf8”理论上不是真正的 UTF-8。“utf8”只支持每个字符最多三个字节,而真正的 UTF-8 是每个字符最多四个字节。本来MySQL 不断没有修复这个 bug,他们在 2010 年发布了一个叫作“utf8mb4”的字符集,绕过了这个问题。他们并没有对这个新的字符集广而告之,以致于目下现今汇集,上仍旧在发起开辟者应用“utf8”,然则这些发起都是毛病的。
简朴归结综合以下:
(1)MySQL 的“utf8mb4”是真正的“UTF-8”。
(2)MySQL 的“utf8”只是一种“专属的编码”,它可以也许编码的 Unicode 字符其实不多。
尚品小编这里发起巨匠:应用“utf8”的 MySQL 和 MariaDB 的用户都该当改用“utf8mb4”,永久都不要再应用“utf8”。
第一、甚么是编码?甚么是 UTF-8?
尽人皆知,计较机贮存的本色是二进制,是应用 0 和 1 来存储文本。比如字符“C”被存成“01000011”,那末计较机在展现这个字符时需求颠末两个步调:
我的电脑将“C”映照成 Unicode 字符鸠合的 67。
我的电脑将 67 编码成“01000011”,并发送给 Web 办事器。
相对的:
计较机读取“01000011”,获得数字 67,因为 67 被编码成“01000011”。
计较机在 Unicode 字符鸠合查找 67,找到了“C”。
几近全体的汇集,应用都应用了 Unicode 字符集,因为没有出处应用其他字符集。
Unicode 字符集包括了上百万个字符。最简朴的编码是 UTF-32,每个字符应用 32 位。如许做最简朴,品牌网站定制,因为不断以来,计较机将 32 位视为数字,而计较机最外行的就是处置数字。但问题是,如许太虚耗空间了。
UTF-8 可以也许节流空间,在 UTF-8 中,字符“C”只需求 8 位,其他的字符或许应用 16 位或 24 位。一篇类似本文如许的文章,假定应用 UTF-8 编码,占用的空间只需 UTF-32 的四分之一阁下。
第二、 MySQL 简史
为甚么 MySQL 开辟者会让“utf8”生效?我们也许可以也许从提交日记中寻找谜底。
MySQL 4.1 版本支持 UTF-8,也就是 2003 年,而明天应用的 UTF-8 标准(RFC 3629)是随后才泛起的。而旧版的 UTF-8 标准(RFC 2279)最多支持每个字符 6 个字节。2002 年 3 月 28 日,MySQL 开辟者在第一个 MySQL 4.1 预览版中应用了 RFC 2279。同年 9 月,他们对 MySQL 源代码举行了一次调解:“UTF8 目下现今最多只支持 3 个字节的序列”。那末是谁提交了这些代码?他为甚么要如许做?这个问题不得而知。在迁移到 Git 后(MySQL 最最早应用的是 BitKeeper),MySQL 代码库中的许多提交者的名字都损失了。2003 年 9 月的邮件列表中也找不到可以也许表明这一厘革的线索。
不外可以也许试着推测一下。
2002 年,MySQL 做出了一个决意:假定用户可以也许包管数据表的每行都应用相反的字节数,那末 MySQL 就可以也许在机能方面来一个大提拔。为此,用户需求将文本列界说为“CHAR”,每个“CHAR”列老是具有相反数量的字符。假定拔出的字符少于界说的数量,MySQL 就会在前面添补空格,假定拔出的字符超越了界说的数量,前面超越部分会被截断。
MySQL 开辟者在最最早试验 UTF-8 时应用了每个字符 6 个字节,CHAR(1) 应用 6 个字节,CHAR(2) 应用 12 个字节,并以此类推。
可以也许说,他们末了的版本才是准确的,惋惜这一版本不断没有发布。然则文档上却写了,而且广为流传,全体晓得 UTF-8 的人都认同文档里写的器械。
不外很明显,MySQL 开辟者或厂商担忧会有效户做这两件事:
应用 CHAR 界说列。
将 CHAR 列的编码设置为“utf8”。
小编推测该当是 MySQL 开辟者正本想匡助那些进展在空间和速度上共赢的用户,但时他们却搞砸了“utf8”编码。
以是效果就是失利的。那些进展在空间和速度上共赢的用户,当他们在应用“utf8”的 CHAR 列时,理论上应用的空间比预期的更大,速度也比预期的慢。而想要准确性的用户,当他们应用“utf8”编码时,却没法留存像“”如许的字符。
第三、为甚么这个问题很引发人们的留心
关于这个问题,小编曾破费许多时光才找到这个 bug。然则不判定这是独一的一个,汇集,上几近全体的文章都把“utf8”当作是真正的 UTF-8。“utf8”只能算是个专有的字符集,它给我们带来了新问题,却不断没有获得管理。