为什么不建议在MySQL中使用 utf8 ?

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 为什么不建议在MySQL中使用 utf8 ?

MySQL 字符编码集中有两套 UTF-8 编码实现:utf8 和 utf8mb4。

如果使用 utf8 的话,存储 emoji 符号和一些比较复杂的汉字、繁体字就会出错。

为什么会这样呢?这篇文章可以从源头给你解答。

何为字符集?

字符是各种文字和符号的统称,包括各个国家文字、标点符号、表情、数字等等。字符集 就是一系列字符的集合。字符集的种类较多,每个字符集可以表示的字符范围通常不同,就比如说有些字符集是无法表示汉字的。

计算机只能存储二进制的数据,那英文、汉字、表情等字符应该如何存储呢?

我们要将这些字符和二级制的数据一一对应起来,比如说字符“a”对应“01100001”,反之,“01100001”对应 “a”。我们将字符对应二进制数据的过程称为"字符编码",反之,二进制数据解析成字符的过程称为“字符解码”。

有哪些常见的字符集?

常见的字符集有 ASCII、GB2312、GBK、UTF-8......。

不同的字符集的主要区别在于:

可以表示的字符范围

编码方式

ASCII

ASCII (American Standard Code for Information Interchange,美国信息交换标准代码) 是一套主要用于现代美国英语的字符集(这也是 ASCII 字符集的局限性所在)。

为什么 ASCII 字符集没有考虑到中文等其他字符呢? 因为计算机是美国人发明的,当时,计算机的发展还处于比较雏形的时代,还未在其他国家大规模使用。因此,美国发布 ASCII 字符集的时候没有考虑兼容其他国家的语言。

ASCII 字符集至今为止共定义了 128 个字符,其中有 33 个控制字符(比如回车、删除)无法显示。

一个 ASCII 码长度是一个字节也就是 8 个 bit,比如“a”对应的 ASCII 码是“01100001”。不过,最高位是 0 仅仅作为校验位,其余 7 位使用 0 和 1 进行组合,所以,ASCII 字符集可以定义 128(2^7)个字符。

由于,ASCII 码可以表示的字符实在是太少了。后来,人们对其进行了扩展得到了 ASCII 扩展字符集 。ASCII 扩展字符集使用 8 位(bits)表示一个字符,所以,ASCII 扩展字符集可以定义 256(2^8)个字符。

11f20e9b9353012df6d8d98d4aff366.png

ASCII字符编码

GB2312

我们上面说了,ASCII 字符集是一种现代美国英语适用的字符集。因此,很多国家都捣鼓了一个适合自己国家语言的字符集。

GB2312 字符集是一种对汉字比较友好的字符集,共收录 6700 多个汉字,基本涵盖了绝大部分常用汉字。不过,GB2312 字符集不支持绝大部分的生僻字和繁体字。

对于英语字符,GB2312 编码和 ASCII 码是相同的,1 字节编码即可。对于非英字符,需要 2 字节编码。

GBK

GBK 字符集可以看作是 GB2312 字符集的扩展,兼容 GB2312 字符集,共收录了 20000 多个汉字。

GBK 中 K 是汉语拼音 Kuo Zhan(扩展)中的“Kuo”的首字母。

GB18030

GB18030 完全兼容 GB2312 和 GBK 字符集,纳入中国国内少数民族的文字,且收录了日韩汉字,是目前为止最全面的汉字字符集,共收录汉字 70000 多个。

BIG5

BIG5 主要针对的是繁体中文,收录了 13000 多个汉字。

Unicode & UTF-8 编码

为了更加适合本国语言,诞生了很多种字符集。

我们上面也说了不同的字符集可以表示的字符范围以及编码规则存在差异。这就导致了一个非常严重的问题:使用错误的编码方式查看一个包含字符的文件就会产生乱码现象。

就比如说你使用 UTF-8 编码方式打开 GB2312 编码格式的文件就会出现乱码。示例:“牛”这个汉字 GB2312 编码后的十六进制数值为 “C5A3”,而 “C5A3” 用 UTF-8 解码之后得到的却是 “ţ”。

你可以通过这个网站在线进行编码和解码:https://www.haomeili.net/HanZi/ZiFuBianMaZhuanHuan

c60fcb11bd2646826ea8e8264d02b50.png

这样我们就搞懂了乱码的本质:编码和解码时用了不同或者不兼容的字符集

62c4c8cefbf6d9cc609d66f60ca83f1.jpg

为了解决这个问题,人们就想:“如果我们能够有一种字符集将世界上所有的字符都纳入其中就好了!”。

然后,Unicode 带着这个使命诞生了。

Unicode 字符集中包含了世界上几乎所有已知的字符。不过,Unicode 字符集并没有规定如何存储这些字符(也就是如何使用二级制数据表示这些字符)。

然后,就有了 UTF-8(8-bit Unicode Transformation Format)。类似的还有 UTF-16、 UTF-32。

UTF-8 使用 1 到 4 个字节为每个字符编码, UTF-16 使用 2 或 4 个字节为每个字符编码,UTF-32 固定位 4 个字节为每个字符编码。

UTF-8 可以根据不同的符号自动选择编码的长短,像英文字符只需要 1 个字节就够了,这一点 ASCII 字符集一样 。因此,对于英语字符,UTF-8 编码和 ASCII 码是相同的。

UTF-32 的规则最简单,不过缺陷也比较明显,对于英文字母这类字符消耗的空间是 UTF-8 的 4 倍之多。

UTF-8 是目前使用最广的一种字符编码,。

033415f8147129b35176e255e20ff9c.png

MySQL 字符集

MySQL 支持很多种字符编码的方式,比如 UTF-8、GB2312、GBK、BIG5。

你可以通过 SHOW CHARSET 命令来查看。

e3d91fe9b9d63598b6b5b2f27561da3.png

通常情况下,我们建议使用 UTF-8 作为默认的字符编码方式。

不过,这里有一个小坑。

MySQL 字符编码集中有两套 UTF-8 编码实现:

utf8 :utf8编码只支持1-3个字节 。在 utf8 编码中,中文是占 3 个字节,其他数字、英文、符号占一个字节。但 emoji 符号占 4 个字节,一些较复杂的文字、繁体字也是 4 个字节。

utf8mb4 :UTF-8 的完整实现,正版!最多支持使用 4 个字节表示字符,因此,可以用来存储 emoji 符号。

为什么有两套 UTF-8 编码实现呢? 原因如下:

74ca5d38e686317384b48f52b204c37.png

因此,如果你需要存储emoji类型的数据或者一些比较复杂的文字、繁体字到 MySQL 数据库的话,数据库的编码一定要指定为utf8mb4 而不是utf8 ,要不然存储的时候就会报错了。

演示一下吧!(环境:MySQL 5.7+)

建表语句如下,我们指定数据库 CHARSET 为 utf8 。

CREATE TABLE `user` (
  `id` varchar(66) CHARACTER SET utf8mb4 NOT NULL,
  `name` varchar(33) CHARACTER SET utf8mb4 NOT NULL,
  `phone` varchar(33) CHARACTER SET utf8mb4 DEFAULT NULL,
  `password` varchar(100) CHARACTER SET utf8mb4 DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

当我们执行下面的 insert 语句插入数据到数据库时,果然报错!

INSERT INTO `user` (`id`, `name`, `phone`, `password`)
VALUES
 ('A00003', 'guide哥😘😘😘', '181631312312', '123456');

报错信息如下:

Incorrect string value: '\xF0\x9F\x98\x98\xF0\x9F...' for column 'name' at row 1

参考

字符集和字符编码(Charset & Encoding):https://www.cnblogs.com/skynet/archive/2011/05/03/2035105.html

十分钟搞清字符集和字符编码:http://cenalulu.github.io/linux/character-encoding/

Unicode-维基百科:https://zh.wikipedia.org/wiki/Unicode

GB2312-维基百科:https://zh.wikipedia.org/wiki/GB_2312

UTF-8-维基百科:https://zh.wikipedia.org/wiki/UTF-8

GB18030-维基百科: https://zh.wikipedia.org/wiki/GB_18030

< END >

也许你还想看

 | 我在 B 站淘了 2 个 Java 实战项目! 小破站,YYDS!

 | 我常用的20+个学习编程的网站!芜湖起飞!

 | 1w+字的 Dubbo 面试题/知识点总结!(2021 最新版)

 | 7年前,24岁,出版了一本 Redis 神书

 | 京东二面:为什么需要分布式ID?你项目中是怎么做的?

 | 再见 Spring Task,这个定时任务框架真香!

 | 一键生成数据库文档,堪称数据库界的Swagger

 | 来看看这个超好用的项目脚手架吧!5分钟搭建一个Spring Boot 前后端分离系统!

 | 看了这些 Java 八股文视频,我直呼好家伙!!!

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
6月前
|
存储 关系型数据库 MySQL
Mysql中utf8和utf8mb4区别
Mysql中utf8和utf8mb4区别
99 0
|
5月前
|
存储 自然语言处理 搜索推荐
mysql中utf8、utf8mb4和utf8mb4_unicode_ci、utf8mb4_general_ci
mysql中utf8、utf8mb4和utf8mb4_unicode_ci、utf8mb4_general_ci
143 0
|
6月前
|
存储 关系型数据库 MySQL
为什么不建议在MySQL中使用 utf8?
MySQL 字符编码集中有两套 UTF-8 编码实现:utf8 和 utf8mb4。 如果使用 utf8 的话,存储 emoji 符号和一些比较复杂的汉字、繁体字就会出错。
|
关系型数据库 MySQL Linux
mysql 8中utf8和utf8mb4运行时的编码警告提醒[Warning]——my.ini配置问题
mysql 8中utf8和utf8mb4运行时的编码警告提醒[Warning]——my.ini配置问题
|
存储 关系型数据库 MySQL
Mysql中utf8和utf8mb4区别
Mysql中utf8和utf8mb4区别
135 0
|
SQL 存储 关系型数据库
MySQL不要再用utf8了
MySQL中真正的UTF-8不是utf8,而是utf8mb4
172 1
MySQL不要再用utf8了
|
SQL 存储 关系型数据库
【MySQL】init_connect='SET NAMES utf8',是干什么的?底层原理是什么?
【MySQL】init_connect='SET NAMES utf8',是干什么的?底层原理是什么?
844 0
|
存储 关系型数据库 MySQL
【MySQL】character-set-server=utf8,是干什么的?底层原理是什么?
【MySQL】character-set-server=utf8,是干什么的?底层原理是什么?
609 0
|
存储 关系型数据库 MySQL
DataX:导入4字节UTF8编码(生僻字)到Mysql数据库的utf8mb4数据表
MySql数据库的编码支持UFT8字符集。utf-8编码可能是2个字节、3个字节、4个字节的字符,MYSQL的utf-8编码,只支持3个字节的字符。汉字中很多生僻字都是4个字节的字符,日常生活中人的姓名就会有很多高位的生僻字。
5988 0
|
关系型数据库 MySQL
mysql编码问题——charset=utf8你真的弄明白了吗?(三)
mysql编码问题——charset=utf8你真的弄明白了吗?(三)
mysql编码问题——charset=utf8你真的弄明白了吗?(三)