参考于今日头条上Java芋道源码的-----记住:永远不要在 MySQL 中使用 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。

这里(https://mathiasbynens.be/notes/mysql-utf8mb4#utf8-to-utf8mb4)提供了一个指南用于将现有数据库的字符编码从 utf8 转成 utf8mb4。

历史原因

为什么 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。

MySQL 数据库字符集 utf8 和 utf8mb4 的区别的更多相关文章

  1. mysql字符集 utf8 和utf8mb4 的区别

    一.导读我们新建mysql数据库的时候,需要指定数据库的字符集,一般我们都是选择utf8这个字符集,但是还会又一个utf8mb4这个字符集,好像和utf8有联系,今天就来解析一下这两者的区别. 二.起 ...

  2. linux下设置mysql数据库字符集utf8

    mysql中文乱码解决方法:将mysql数据库编码统一utf8 查看数据库编码: show variables like 'character%'; 编辑/etc/my.cnf [mysql] def ...

  3. inux下设置mysql数据库字符集utf8

    mysql中文乱码解决方法:将mysql数据库编码统一utf8 查看数据库编码: ? 1 <span style="font-size: 16px;"><stro ...

  4. mysql字符集utf8和utf8mb4区别

    1.起因 公司游戏项目上线第一天,出现单个区服异常宕机的问题,根据日志排查下来,连接数据的时候报错,后面排查是因为有玩家插入Emoji 等表情导致无法存储如数据库,数据库字符集编码为utf8,后续改成 ...

  5. MySQL中 utf8与utf8mb4的区别

    MySQL中 utf8与utf8mb4的区别 一.简介 ​ MySQL在5.5.3之后增加了这个utf8mb4的编码,mb4就是most bytes 4的意思,专门用来兼容四字节的unicode.好在 ...

  6. 【记录】mysql中建表utf8和utf8mb4区别?timestamp和datetime区别?

    mysql中建表utf8和utf8mb4区别? 1:utf8 是 Mysql 中的一种字符集,只支持最长三个字节的 UTF-8字符,也就是 Unicode 中的基本多文本平面 2:要在 Mysql 中 ...

  7. 查看和设置MySQL数据库字符集(转)

    查看和设置MySQL数据库字符集作者:scorpio 2008-01-21 10:05:17 标签: 杂谈 Liunx下修改MySQL字符集:1.查找MySQL的cnf文件的位置find / -ina ...

  8. 使用SQL语句修改Mysql数据库字符集的方法

    使用SQL语句修改Mysql数据库字符集的方法   修改库: alter database [$database] character set [$character_set] collate [$c ...

  9. MySQL数据库之MyISAM与InnoDB的区别

    MySQL数据库之MyISAM与InnoDB的区别 从以下几个方面: 1.存储结构 每个MyISAM在磁盘上存储成三个文件.第一个文件的名字以表的名字开始,扩展名指出文件类型. .frm文件存储表定义 ...

随机推荐

  1. 如何使你的Ajax应用内容可让搜索引擎爬行

    This document outlines the steps that are necessary in order to make your AJAX application crawlable ...

  2. 利用webmagic获取天猫评论

    引言 爬取商品信息 爬取商品评论 数据清洗 1. 引言 现代网页往往其HTML只有基本结构,而数据是通过AJAX或其他方法获取后填充,这样的模式对爬虫有一定阻碍,但是熟练以后获取并不困难,本文以爬取天 ...

  3. 洛谷 P1272 解题报告

    P1272 重建道路 题目描述 一场可怕的地震后,人们用\(N\)个牲口棚\((1≤N≤150\),编号\(1..N\))重建了农夫\(John\)的牧场.由于人们没有时间建设多余的道路,所以现在从一 ...

  4. struts升级2.3.12到2.5.13

    参考文章: http://www.ituring.com.cn/article/495914 http://blog.csdn.net/zhangchen1987/article/details/78 ...

  5. Python_替换当前目录下文件类型

    ''' 将当前目录的所有扩展名为html的文件重命名为扩展名为htm的文件 方法一 ''' import os file_list=os.listdir('.') for filename in fi ...

  6. spring中jedis对redis的事务使用注意总结

    spring的@Transactional不支持redis的事务,并且redis的事务和其它关系型数据库的事务概念不是太一样,redis事务不支持回滚,并且一条命令出错后,后面的命令还会执行. 所以不 ...

  7. Tiny4412中断之看门狗

    一:看门狗(WDT watch dog timer) 看门狗其实是一个计数器,它的作用就是防止程序陷入死循环或者程序运行跑飞:看门狗是一个硬件,它的工作原理是,初始化给他一个值,它会过一段时间减一,直 ...

  8. webpack + vue 在dev和production模式下的小小区别

    上周的某一天,和一位同样是前端技术极度爱好的开发者朋友聊天,他在提出了一个问题,他写的vue程序为什么在dev模式运行良好,而在production模式就直接报错了.这让我感到惊讶,还有这么神奇的事情 ...

  9. eclipse如何新建项目发布到git

    1.首先去查询本地git仓库地址 2.找到项目位置  删除git版本 3.更换git提交目标地址  目标地址是新建的git仓库地址 4.提交

  10. tkiner中Radiobutton单选框控件(七)

    Radiobutton控件 由于本次内容中好多知识都是之前重复解释过的,本次就不做解释了.不太清楚的内容请参考tkinter1-6节中的内容 import tkinter wuya = tkinter ...