用MySQL的朋友们请不要使用"utf8",请使用"utf8mb4"

今天我试图把UTF-8编码的字符串插入使用“utf8”编码的MariaDB数据库中,Rails抛出一个古怪的异常:

一切都很UTF-8:UTF-8 client,UTF-8的服务器,UTF-8编码的数据库,使用UTF-8的字符集。“

但是问题的关键是:MySQL数据库的 “utf8”并不是真正概念里的 UTF-8。

MySQL中的“utf8”编码只支持最大3字节每字符。真正的大家正在使用的UTF-8编码是应该能支持4字节每个字符。

MySQL的开发者没有修复这个bug。他们在2010年增加了一个变通的方法:一个新的字符集“utf8mb4”

当然,他们并没有对外公布(可能因为这个bug有点尴尬)。现在很多指南推荐用户使用“utf8”其实都错了。

简单的说:

MySQL中的 “utf8mb4” 才是 真正意义上的“UTF-8”。

MySQL的“utf8”是个“特殊的字符编码”。这种编码很多Unicode字符保存不了。

我强烈建议MySQL和MariaDB用户使用“utf8mb4”而不是“utf8”。

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

Joel on Software上有一遍我最喜欢的介绍,我精简描述如下:

计算机使用0和1存储文字。比如第一段第一个字符存储为“01000011”表示“C”,计算机通过以下两个步骤选择用“C”表示:

计算机读取到“01000011”后计算出这是数字67。

计算机通过查找Unicode字符集来确认67代表的“C”。

同样的事情发生在我打字输入C的时候。

计算机通过Unicode字符集将“C” 映射为67。

计算机把67编码为“01000011”发送给web服务器。

几乎所有的程序和互联网应用使用Unicode字符集。

Unicode字符集里有超过100万个字符(“C” 和 “” 是两种不同的字符。)。UTF-32是最简单的编码方式,它在表示每个字符的时候使用32个bits。这样编码简单,但是并不实用,明显浪费了太多的空间。

UTF-8相比UTF-32更加节约空间。在UTF-8中,像“C”这样的字符占用8bits,“”这样的占用32 bits。其他字符占用16或者24 bits。如本篇这样的文章用UTF-8存储比用UTF-32节省4倍左右的空间。更小的空间占用也意味着加载速度会快上4倍。

而MySQL中的 “utf8”字符集则和其他应用行为不一样。比如根本没法表示“”。

一点关于MySQL的历史

为什么MySQL的开发者开发了一个奇怪的“utf8”。我们可以通过提交的日志来揣测一下。

MySQL从4.1版开始支持UTF-8。那是在比今天UTF-8 RFC 3629标准更早的2003年。

在此之前的UTF-8标准,RFC 2279中规定6个bytes表示一个字符。MySQL的开发者在2002.3.28编码实现了RFC 2279 。并发布了pre-pre-release 的 MySQL 4.1

然后在9月出现了一个神秘的字节调整。“UTF8 now works with up to3 byte sequences only.”

是谁提交了这次更新?为什么?我无法解答。MySQL的源码移到Git后丢失了旧的作者信息(MySQL 曾经和linux内核一样使用BitKeeper)

但是我大概能猜出来原因。

回到2002年,如果用户可以保证表中的每一行具有相同的字节数,MySQL就可以提高用户的速度。为了得到这个提升,用户就需要定义保存文字的列为“CHAR”。一个“CHAR”列总是拥有相同的字符数。如果存入的字符较少则会在最后补齐空白。如果存入的数据过多则会被抛弃多余的字符。

当MySQL的开发者第一次尝试以6字节每字符实现UTF-8时,他们意识到CHAR(1)的列会占用6字节,CHAR(2)会占用12字节,以此类推。

显而易见的是,这个没有被使用的实现方式是正确的,任何一个理解UTF-8的开发者将会认同这一点。

我的猜测是:MySQL的开发者违背了“utf8”编码去帮助那些1)试图去优化空间和速度的人,2)尝试优化空间和速度失败的人。

这是个无人获益的改动。那些想要更快性能,更小空间的得到的依然是比他们曾经使用版本更大更慢的实现,而那些想要正确的“utf8”的人得到的是个“”都存储不了的实现。

MySQL发布了这个错误的版本后,在也没有修复它:因为那样很多使用者将被迫重建他们的数据库。MySQL最终在2010年更新了一个以“utf8mb4”命名的UTF-8实现。

Why it’s so frustrating

这周我过得很操蛋。我遇到一个很难发现的bug,就因为我被“utf8”这个名字给愚弄了。而且我也不是个案,我发现几乎每篇推荐使用“utf8”的文章都错了。

“utf8”的命名在mysql依然是错的。这是个专有的实现。这造成了新的问题,而且没有解决他应该解决的问题。

如果你使用MySQL或者 MariaDB,不要使用“utf8”,应该总是使用“utf8mb4”,否则总有一天会遇到头疼的事情。

译文 | https://www.jianshu.com/p/ab9aa8d4df7d

编码utf-8的不可映射字符_MySQL 请不要使用“utf8”相关推荐

  1. mysql concat 不同字符集_字符编码 - 如何将整个MySQL数据库字符集和排序规则转换为UTF-8?...

    字符编码 - 如何将整个MySQL数据库字符集和排序规则转换为UTF-8? 如何将整个MySQL数据库字符集转换为UTF-8并将整理转换为UTF-8? 17个解决方案 591 votes 使用utf8 ...

  2. 错误: 编码 GBK 的不可映射字符 (0x80)

    在我想要在命令行使用println输出一些中文的时候,发现编码出现错误 原因: java程序在编译的时候,需要使用JDK开发工具包中的JAVAC.EXE命令,而JDK开发工具包是国际版的,默认格式为U ...

  3. java编码gbk的不可_解决 java “错误:编码GBK 的不可映射字符”

    在cmd控制台编译时报错:编码GBK的不可映射字符 检查: 1. 查本机区域语言设置中文没有问题 2. 此程序可以在eclipse上正常运行 右键properties-resource-text fi ...

  4. java “错误:编码GBK 的不可映射字符”

    目录 前言 一.透过现象看本质,发现问题找原因 1.查看cmd的默认编码格式: 2.查看代码文件的保存格式: 二.分析问题原因,寻找解决方案 1.指定DOS命令的编码格式: 2.修改代码文件的编码格式 ...

  5. JNI编译时错误 编码GBK的不可映射字符 解决方法

    使用Android studio 进行JNI开发时,在java代码中声明好了native方法后需要使用javah指令生成.h头文件,此时出现如下错误提示: D:\ASworkspace\XXXX(工程 ...

  6. 使用cmd打开java文件,报错:“错误,编码GBK的不可映射字符”

    使用cmd打开java文件,报错:"错误,编码GBK的不可映射字符" 今天使用EditPlus写了一个小程序,用cmd运行时报错--"错误,编码GBK的不可映射字符&qu ...

  7. 【错误记录】生成 Java 文档错误 ( Xxx.java:xx: 错误: 编码GBK的不可映射字符 )

    文章目录 一.报错信息 二.解决方案 一.报错信息 使用 javadoc 命令 , 生成 Java 文档 , 报错 ; javadoc Student.java D:\develop\javadoc& ...

  8. Gradle: 警告:编码 GBK 的不可映射字符

    2019独角兽企业重金招聘Python工程师标准>>> 不能识别java程序中的中文 使用了新的开发环境Android studio Gradle: 警告:编码 GBK 的不可映射字 ...

  9. JAVA错误日志(part1)--编码GBK的不可映射字符

    学习笔记,仅供参考 错误 当Java源代码中包含中文字符时,我们在用javac编译时可能出现错误: 错误: 编码GBK的不可映射字符 错误原因 由于JDK是国际版的,我们在用javac编译时,编译程序 ...

最新文章

  1. 聊聊rocketmq的ProducerImpl
  2. BizTalk开发系列(二十三) BizTalk性能指标参考
  3. 编译32位_玩转Android10源码开发定制(11)内核篇之安卓内核模块开发编译
  4. Redis HyperLogLog
  5. Java多线程学习三十五: CyclicBarrier 和 CountDownLatch 有什么不同
  6. linux pinctl 分析,Linux驱动架构之pinctrl子系统分析(一)
  7. Squid服务器配置
  8. [转]引用 VC 对话框设置位图背景并透明控件
  9. Java学习路线(转)
  10. Matlab的最优化实现方法之线性规划:linprog
  11. 深度学习——分类网络的总结(持续更新ing~)
  12. nginx 基本入门
  13. extern “C”的使用
  14. Mathematica 命令大全
  15. Ubuntu卸载、安装
  16. 从0开发游戏引擎之引擎基础组件-Node类实现
  17. quartz - 宕机后的设置
  18. [MRCTF2020]套娃
  19. Java扑克牌24点运算
  20. STM32标准库的引入视频课程-第3季第6部分-朱有鹏-专题视频课程

热门文章

  1. 项目: 图书管理系统 【C++ / C】
  2. html页面显示html代码怎么写,求助这段代码如何转换成正常可看的HTML页面
  3. python中for循环和while循环的区别_Python中for循环和while循环有什么区别?
  4. 催收系统服务器,催收系统安装文档/ 环境搭建 /测试服务器 java工程启动文档
  5. java读取文件 16进制_Java对文件的16进制读取和操作
  6. 【Java】6.7 内部类
  7. 一定是你想要的微服务资源springboot、springcloud、docker、dubbo
  8. 带你学python基础:面向对象编程
  9. 蓝桥杯-拿糖果(java)
  10. Android踩坑日记:FloatingActionButton的设置大小问题