iis服务器助手广告广告
返回顶部
首页 > 资讯 > 数据库 >记住:永远不要在 MySQL 中使用 UTF-8
  • 222
分享到

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

2024-04-02 19:04:59 222人浏览 八月长安
摘要

阅读本文大概需要 3.6 分钟。 译文:Http://suo.im/4zBuvs 来自:http://ju.outofmemory.cn 最近我遇到了一个bug,我试着通过Rails在以“

阅读本文大概需要 3.6 分钟。

译文:Http://suo.im/4zBuvs

来自:http://ju.outofmemory.cn

最近我遇到了一个bug,我试着通过Rails在以“utf8”编码的MariaDB中保存一个UTF-8字符串,然后出现了一个离奇的错误:


Incorrect string value:‘\xF0\x9F\x98\x83 <…’ 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”。


·END·

程序员的成长之路

路虽远,行则必至

本文原发于 同名微信公众号「程序员的成长之路」,回复「1024」你懂得,给个赞呗。

回复 [ 520 ] 领取程序员最佳学习方式

回复 [ 256 ] 查看 Java 程序员成长规划


往期精彩回顾

推荐 11 个 GitHub 上比较热门的 Java 项目

分库分表?如何做到永不迁移数据和避免热点?

linux运维宝典:最常用的150个命令汇总

工作发狂:mybatis 中$和#千万不要乱用!

分享一些好用的 Chrome 扩展

我爸的电脑中了勒索病毒……

P7 黑客是如何发现女朋友出轨的,痛心的经历!



您可能感兴趣的文档:

--结束END--

本文标题: 记住:永远不要在 MySQL 中使用 UTF-8

本文链接: https://www.lsjlt.com/news/46647.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 为什么永远不要在MySQL中使用UTF-8
    这篇文章给大家介绍为什么永远不要在MySQL中使用UTF-8,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。最近我遇到了一个bug,我试着通过Rails在以“utf8”编码的MariaDB中保存一个UTF-8字符串,然后...
    99+
    2023-06-19
  • 为何不要在MySQL中使用UTF-8编码方式详解
    MySQL的UTF-8编码方式 MySQL 从 4.1 版本开始支持 UTF-8,也就是 2003 年,然而目前流行的UTF-8 标准(RFC 3629)是在此之后规定的。正因此,才造就了MySQL中的U...
    99+
    2024-04-02
  • 为什么不建议在 MySQL 中使用 UTF-8?
    最近我遇到了一个bug,我试着通过Rails在以“utf8”编码的MariaDB中保存一个UTF-8字符串,然后出现了一个离奇的错误:Incorrect string value:&nb...
    99+
    2024-04-02
  • 永远不要在 MySQL 中使用 utf8,使用 utf8mb4 作为代替
    今天的错误:我试图在 MariaDB 「utf8」 编码的数据库中存储一个 UTF-8 字符串,Rails 出现了一个奇怪的错误:Incorrect string value: ‘\xF0\x9F\x98\x8...
    99+
    2022-11-16
    utf8mb4 mysql
  • MySQL中如何使用UTF-8编码
    这期内容当中小编将会给大家带来有关MySQL中如何使用UTF-8编码,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。那么什么是编码什么是UTF-8我们都知道,计算机使用0和...
    99+
    2024-04-02
  • 怎么在JavaScript中使用cookie记住用户页面
    本篇文章为大家展示了怎么在JavaScript中使用cookie记住用户页面,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。什么时cookie?cookie有4kb大小,超出长度会返回空字符串;coo...
    99+
    2023-06-14
  • html中不要忘记使用结束标签
    这篇文章给大家分享的是有关html中不要忘记使用结束标签的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。     HTML段落     ...
    99+
    2024-04-02
  • mysql能不能在linux中使用
    这篇文章主要讲解了“mysql能不能在linux中使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“mysql能不能在linux中使用”吧!mysql能在linux中使用。mysql是一个跨...
    99+
    2023-07-02
  • 在MySQL中为何不建议使用utf8
    目录何为字符集?有哪些常见的字符集?ASCIIGB2312GBKGB18030BIG5Unicode & UTF-8 编码mysql 字符集MySQL 字符编码集中有两套 UTF-8 编码实现:utf8 和 ut...
    99+
    2024-04-02
  • 为什么不要在 Flutter 中使用全局变量
    目录前言Flutter 中的全局变量是什么?Flutter 中使用全局变量的缺点1. 复杂的代码维护过程2. 全局变量使单元测试变得痛苦3. 全局变量导致“面条&rdqu...
    99+
    2024-04-02
  • User这个词为什么不要在代码中使用
    今天给大家介绍一下User这个词为什么不要在代码中使用。文章的内容小编觉得不错,现在给大家分享一下,觉得有需要的朋友可以了解一下,希望对大家有所帮助,下面跟着小编的思路一起来阅读吧。当你意识到你在项目开始时做的轻量、简单的设想竟然完全错了时...
    99+
    2023-06-28
  • 如何在 Go 中使用不记名令牌发出请求
    最近发现不少小伙伴都对Golang很感兴趣,所以今天继续给大家介绍Golang相关的知识,本文《如何在 Go 中使用不记名令牌发出请求》主要内容涉及到等等知识点,希望能帮到你!当然如果阅读本文时存在...
    99+
    2024-04-04
  • 想要在 Laravel 中使用 ASP IDE 记录的日志,该怎么做?
    Laravel 是一个流行的 PHP 框架,而 ASP IDE 是一个功能强大的集成开发环境(IDE),用于开发 ASP.NET 应用程序。在 Laravel 应用程序中记录日志是一个非常重要的任务,它可以帮助我们诊断应用程序中的问题并找到...
    99+
    2023-10-14
    ide 日志 laravel
  • MySQL concat() 创建要在查询中使用的列名?
    要创建要在查询中使用的列名称,您需要通过 set 命令使用用户定义的变量。语法如下 -SET @anyVariableName := ( SELECT CONCAT ( "SELECT",...
    99+
    2023-10-22
  • 在PHP中使用MySQL时,是否需要转义0值?
    在PHP中使用MySQL时,是否需要转义0值? 在编写PHP应用程序时,通常会涉及到与MySQL数据库进行交互,其中涉及到向数据库中插入、更新或查询数据的操作。在进行数据处理时,安全性...
    99+
    2024-02-28
    mysql php 转义
  • 为什么在MySQL中几乎不使用分区表
    这篇文章主要介绍“为什么在MySQL中几乎不使用分区表”,在日常操作中,相信很多人在为什么在MySQL中几乎不使用分区表问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”为什么在...
    99+
    2024-04-02
  • 日志记录在Java中有多重要?如何使用NPM包来实现?
    在Java应用程序开发过程中,日志记录是必不可少的一部分。在开发过程中,我们需要时刻监测应用程序的运行状态,以便及时发现问题并及时处理。因此,在应用程序中添加日志记录是至关重要的。 那么,在Java中如何实现日志记录呢?我们可以使用Jav...
    99+
    2023-10-07
    日志 npm numy
  • 为什么要在Java项目中使用Numy作为日志记录工具?
    在Java项目中使用Numy作为日志记录工具有很多好处。Numy是一种基于日志的分析工具,可以帮助开发人员更好地监控和分析应用程序的行为和性能。 首先,Numy可以帮助开发人员更好地了解应用程序的运行情况。通过记录应用程序的日志信息,Num...
    99+
    2023-10-07
    日志 npm numy
  • dockerfile使用记录:在生产中使用dockerfile构建mysql详细教学加案例
    dockerfile使用记录:在生产中使用dockerfile构建mysql详细教学加案例 1.1 Dockerfile是用于构建Docker镜像的一种文本文件,其中包含指令和参数。MySQL的Doc...
    99+
    2023-09-03
    mysql 数据库 docker
  • Path索引文件:Go语言中使用它,永远不必再为文件查找而烦恼!
    在进行文件操作时,经常需要查找特定目录下的文件。但是,随着文件数量的增加,查找速度也会变得越来越慢。为了提高文件查找的速度,我们可以使用Path索引文件。 Path索引文件是一种索引文件,用于存储目录下的文件信息。它会在后台自动更新,以确...
    99+
    2023-10-05
    path 索引 文件
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作