加入收藏 | 设为首页 | 会员中心 | 我要投稿 河北网 (https://www.hebeiwang.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程 > 正文

记住:永远不要在MySQL中使用UTF-8

发布时间:2019-04-15 20:21:18 所属栏目:编程 来源:佚名
导读:最近我碰着了一个bug,我试着通过Rails在以utf8编码的MariaDB中生涯一个UTF-8字符串,然后呈现了一个怪僻的错误: Incorrectstringvalue:xF0x9Fx98x83forcolumnsummaryatrow1 我用的是UTF-8编码的客户端,处事器也是UTF-8编码的,数据库也是,就连要保

 记着:永久不要在MySQL中行使UTF-8

最近我碰着了一个bug,我试着通过Rails在以“utf8”编码的MariaDB中生涯一个UTF-8字符串,然后呈现了一个怪僻的错误:

  1. Incorrect string value:‘xF0x9Fx98x83 <…’ for column ‘summary’ at row 1 

我用的是UTF-8编码的客户端,处事器也是UTF-8编码的,数据库也是,就连要生涯的这个字符串“ <…”也是正当的UTF-8。

题目的症结在于,MySQL的“utf8”现实上不是真正的UTF-8。

“utf8”只支持每个字符最多三个字节,而真正的UTF-8是每个字符最多四个字节。

MySQL一向没有修复这个bug,他们在2010年宣布了一个叫作“utf8mb4”的字符集,绕过了这个题目。

虽然,他们并没有对新的字符集广而告之(也许是由于这个bug让他们认为很忧伤),甚至于此刻收集上如故在提议开拓者行使“utf8”,但这些提议都是错误的。

简朴归纳综合如下:

1.MySQL的“utf8mb4”是真正的“UTF-8”。

2.MySQL的“utf8”是一种“专属的编码”,它可以或许编码的Unicode字符并不多。

我要在这里澄清一下:全部在行使“utf8”的MySQL和MariaDB用户都应该改用“utf8mb4”,永久都不要再行使“utf8”。

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

我们都知道,计较机行使0和1来存储文本。好比字符“C”被存成“01000011”,那么计较机在表现这个字符时必要颠末两个步调:

1.计较机读取“01000011”,获得数字67,由于67被编码成“01000011”。

2.计较机在Unicode字符齐集查找67,找到了“C”。

同样的:

1.我的电脑将“C”映射成Unicode字符齐集的67。

2.我的电脑将67编码成“01000011”,并发送给Web处事器。

险些全部的收集应用都行使了Unicode字符集,由于没有来由行使其他字符集。

Unicode字符集包括了上百万个字符。最简朴的编码是UTF-32,每个字符行使32位。这样做最简朴,由于一向以来,计较机将32位视为数字,而计较机最在行的就是处理赏罚数字。但题目是,这样太挥霍空间了。

UTF-8可以节减空间,在UTF-8中,字符“C”只必要8位,一些不常用的字符,好比“”必要32位。其他的字符也许行使16位或24位。一篇相同本文这样的文章,假如行使UTF-8编码,占用的空间只有UTF-32的四分之一阁下。

MySQL的“utf8”字符集与其他措施不兼容,它所谓的“”,也许真的是一坨……

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开拓者或厂商担忧会有效户做这两件事:

1.行使CHAR界说列(在此刻看来,CHAR已经是老骨董了,但在当时,在MySQL中行使CHAR会更快,不外从2005年往后就不是这样子了)。

2.将CHAR列的编码配置为“utf8”。

我的揣摩是MySQL开拓者原来想辅佐那些但愿在空间和速率上双赢的用户,但他们搞砸了“utf8”编码。

以是功效就是没有赢家。那些但愿在空间和速率上双赢的用户,当他们在行使“utf8”的CHAR列时,现实上行使的空间比预期的更大,速率也比预期的慢。而想要正确性的用户,当他们行使“utf8”编码时,却无法生涯像“”这样的字符。

在这个不正当的字符集宣布了之后,MySQL就无法修复它,由于这样必要要求全部用户从头构建他们的数据库。最终,MySQL在2010年从头宣布了“utf8mb4”来支持真正的UTF-8。

为什么这件工作会让人云云抓狂

由于这个题目,我整整抓狂了一个星期。我被“utf8”愚弄了,花了许多时刻才找到这个bug。但我必然不是独一的一个,收集上险些全部的文章都把“utf8”当成是真正的UTF-8。

“utf8”只能算是个专有的字符集,它给我们带来了新题目,却一向没有获得办理。

总结

假如你在行使MySQL或MariaDB,不要用“utf8”编码,改用“utf8mb4”。这里( https://mathiasbynens.be/notes/mysql-utf8mb4#utf8-to-utf8mb4 )提供了一个指南用于将现稀有据库的字符编码从“utf8”转成“utf8mb4”。

【编辑保举】

  1. 抛开伟大的架构计划,MySQL优化头脑根基都在这了
  2. MySQL常识系统——索引
  3. 2019年4月数据库风行度排行:Oracle一连增添股价获新高
  4. 1000行MySQL进修条记,不怕你不会,就怕你不学!
  5. 一次诡异的线上数据库的死锁题目排查进程
【责任编辑:庞桂玉 TEL:(010)68476606】
点赞 0

(编辑:河北网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读