今天的错误:我试图将一个UTF-8字符串存储在MariaDB“utf8”编码的数据库中,而且引起了一个奇怪的错误:
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开发人员从未修复过这个bug。他们在
2010年发布了一个解决方法:一个名为“ utf8mb4 ” 的新字符集。
固然,他们从未公布过这个(多是由于这个bug太尴尬了)。如今,Web上的指南建议用户使用“utf8”。全部这些指南都是错误的。
· MySQL的“utf8mb4”表示“UTF-8”。
· MySQL的“utf8”意味着“专有字符编码”。此编码不能编码许多Unicode字符。
我将在这里作一个完全的陈述:目前使用“utf8”的全部 MySQL和MariaDB用户实际上应该使用“utf8mb4”。没有人应该使用“utf8”。
什么是编码?什么是UTF-8?
Computer(计算机)将文本存储为1和0。本段中的第一个字母存储为“01000011”,你的计算机显示为“C”。你的计算机分两步选择“C”:
1. 你的计算机读取“01000011”并肯定它是数字67.这是由于67被编码为“01000011”。
2. 你的计算机在
Unicode 字符集中查找字符编号67 ,而且发现67表示“C”。
1. 个人计算机将Unicode字符集中的“C”映射到67。
2. 个人计算机编码为 67,向此Web服务器发送“01000011”。
字符集是一个解决的问题。几乎互联网上的每一个程序都使用Unicode字符集,由于没有动机使用另外一个。
但编码更像是一种判断。Unicode具备超过一百万个字符的插槽。(C和“💩”是两个字符)
最简单的编码(utf-32)使每一个字符占用32位。这很简单,由于计算机已经把32位的组看成数字处理了不少年,并且他们真的很擅长。但它没用:这是浪费空间。
UTF-8节省空间。在UTF-8中,像“C”这样的常见字符占8位,而像“其余字符须要16或24位。像这样的博客文章在UTF-8中占用的空间比在UTF-32中少四倍。因此加载速度快四倍。
你可能没有意识到,但咱们的计算机在幕后赞成了UTF-8。若是他们没有,而后当我输入
MySQL的“utf8”字符集与其余程序不一致。当他们说“💩”时,它会犹豫。
一点MySQL的历史
为何MySQL开发人员使“utf8”无效?咱们能够经过查看提交日志来猜想。
MySQL从版本4.1开始支持UTF-8 。那是2003年 - 在今天的UTF-8标准以前,RFC 3629。
之前的UTF-8标准RFC 2279每一个字符最多支持6个字节。MySQL开发人员在2002年3月28日的MySQL 4.1的第一个预发行版本中编写了RFC 2279 。
而后在9月对MySQL的源代码进行了一次神秘的,一字节的调整:“UTF8如今只能处理3个字节的序列。”
是谁提交了这个?为何?我说不出来。MySQL的代码库在采用Git时彷佛丢失了旧的做者名称。(MySQL过去经常使用BitKeeper,就像Linux内核同样。)2003年9月左右的邮件列表中没有任何内容能够解释这一变化。
早在2002年,若是用户能够保证表中的每一行具备相同的字节数,MySQL就会为用户提供速度提高。为此,用户会将文本列声明为“CHAR”。“CHAR”列始终具备相同的字符数。若是你输入的字符太少,它会在末尾添加空格; 若是你输入太多的字符,它会截断最后的字符。
当MySQL开发人员第一次尝试使用UTF-8时,每一个字符的后六个字节,他们可能会犹豫不决:一个CHAR(1)列须要六个字节; CHAR(2)列须要12个字节; 等等。
让咱们明确一点:从未发布的初始行为是正确的。它获得了很好的记录和普遍采用,任何理解UTF-8的人都会赞成这是正确的。
但显然,MySQL开发人员(或商人)担忧一两个用户会作两件事:
1.选择CHAR列。(CHAR格式如今是遗物。当时,使用CHAR列,MySQL速度更快。直到2005年,它不是。)
个人猜想是MySQL开发人员打破了他们的“utf8”编码来帮助这些用户:1)试图优化空间和速度的用户; 2)未能优化速度和空间。
没人赢。想要速度和空间的用户使用“utf8”CHAR列仍然是错误的,由于那些列仍然比它们原来更大更慢。想要正确性的开发人员使用“utf8”是错误的,由于它没法存储
一旦MySQL发布了这个无效的字符集,它就永远没法解决它:这将迫使每一个用户重建每一个数据库。MySQL最终在2010年发布了UTF-8支持,名称不一样:“utf8mb4”。
为何这么使人沮丧
很明显,本周我很沮丧。个人bug很难找到,由于我被“utf8”这个名字所迷惑。并且我不是惟一一个 - 我在网上发现的几乎全部文章都将“utf8”称为UTF-8。
名称“utf8”始终是错误的。这是一个专有的字符集。它创造了新问题,并无解决它要解决的问题。
1.Database systems have subtle bugs and oddities, and you can avoid a lot of bugs by avoiding database systems.
2.If you need a database, don’t use MySQL or MariaDB. Use PostgreSQL.
3.If you need to use MySQL or MariaDB, never use “utf8”. Always use “utf8mb4” when you want UTF-8. Convert your database now to avoid headaches later.
联系邮箱:public@space-explore.com