点击上方“方志朋”,选择“设为星标”

回复”666“获取新整理的面试文章

最近遇到几个项目被MySQL的utf8编码坑,想起之前编码问题被坑的惨痛教训,记录一下,警示自己。

曾几何时,每次建库都选utf8,觉得自己比那些用乱七八糟编码的人不知道酷到哪里去了。直到好多年前的某次课程设计做项目的时候,愉快的建了个用户表:

CREATE TABLE `test_user` (`id` int(11) unsigned NOT NULL AUTO_INCREMENT,`name` varchar(32) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

然后愉快的新增用户:INSERT INTO test_user(name) VALUES("我是????"),接着愉快的反思人生:

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

我是谁?我来自哪里?我在干嘛?难道是我代码里面的字符集用错了?不对啊我所有地方都用的utf8啊……

# MySQL的UTF8编码是什么?

首先来看官方文档:

The character set named utf8 uses a maximum of three bytes per character and contains only BMP characters. The utf8mb4 character set uses a maximum of four bytes per character supports supplementary characters:

For a BMP character, utf8 and utf8mb4 have identical storage characteristics: same code values, same encoding, same length.

For a supplementary character, utf8 cannot store the character at all, whereas utf8mb4 requires four bytes to store it. Because utf8 cannot store the character at all, you have no supplementary characters in utf8 columns and need not worry about converting characters or losing data when upgrading utf8 data from older versions of MySQL.

我们再看看维基百科对UTF8编码的解释:

UTF-8 is a variable width character encoding capable of encoding all 1,112,064 valid code points in Unicode using one to four 8-bit bytes.

可以看出,MySQL中的utf8实质上不是标准的UTF8。MySQL中,utf8对每个字符最多使用三个字节来表示,所以一些emoji甚至是一些生僻汉字就存不下来了,比如“????”。

MySQL一直不承认这是一个bug,他们在2010年发布了“utf8mb4”字符集来绕过这个问题,在MySQL中,utf8mb4才应该是标准的utf8编码,并且官方很鸡贼的偷偷在最新的文档中加上了,算是认识到错误了吧:

utf8 is an alias for the utf8mb3 character set.

The utf8mb3 character set will be replaced by utf8mb4 in some future MySQL version. Although utf8 is currently an alias for utf8mb3, at that point utf8 will become a reference to utf8mb4. To avoid ambiguity about the meaning of utf8, consider specifying utf8mb4 explicitly for character set references instead of utf8.

# MySQL UTF8问题简史

MySQL从4.1版本开始支持utf8,即2003年,但是现在的utf8标准(RFC 3629)是在其后发布的。MySQL在2002年3月28日的4.1预览版中使用了旧版的utf8标准(RFC 2279),该标准最多支持每个字符6个字节,同年9月MySQL调整其utf8字符集最多支持3字节,而这个调整可能只是为了优化空间(05年前推荐使用CHAR类字段,而一个utf8的CHAR将会占用6字节长度)和时间性能(05年前在MySQL中使用CHAR字段会有更优的速度)。嗯可以在GitHub中看到大家对这个坑的吐槽:

但是这个字符编码发布出来,就不能轻易的修改,因为如果已经有用户开始使用了,就需要这些用户重新构建其数据库。

怎么补救呢?在上面最新文档中可以看出,他们将当前的utf8作为utf8mb3的别名,并且在将来的某一天会把utf8重新作为utf8mb4别名,这样来解决这个多年的巨坑。

# 啥是UTF8

# utf8mb4_unicode_ci 和 utf8mb4_general_ci

字符除了存储,还需要排序或者比较,这个操作与编码字符集有关,称为collation,与utf8mb4对应的是utf8mb4_unicode_ci 和 utf8mb4_general_ci这两个collation。

准确性

utf8mb4_unicode_ci 是基于标准Unicode来进行排序比较的,能保持在各个语言之间的精确排序;

utf8mb4_general_ci 并不基于Unicode排序规则,因此在某些特殊语言或者字符上的排序结果可能不是所期望的。

性能

utf8mb4_general_ci 在比较和排序时更快,因为其实现了一些性能更好的操作,但是在现代服务器上,这种性能提升几乎可以忽略不计。

utf8mb4_unicode_ci 使用Unicode的规则进行排序和比较,其排序规则为了处理一些特殊字符,实现更加复杂。

现在基本没有理由继续使用utf8mb4_general_ci了,因为其带来的性能差异很小,远不如更好的数据设计,比如使用索引等等。

# MySQL用错编码怎么救

  1. 备份,不然崩了就只有删库跑路了;

  2. 升级MySQL服务端到5.3.3及以上版本,以支持utf8md4;

  3. 将数据库、表、列的字符编码、collation改为utf8md4:

# For each database:
ALTER DATABASE database_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
# For each table:
ALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
# For each column:
ALTER TABLE table_name CHANGE column_name column_name VARCHAR(length) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

4.检查列和索引键的最大长度;

5.修改连接、客户端、服务端的字符集;

6.修复和优化所有的表,以免出现一些莫名其妙的错误,可以使用如下的方式:

# For each table
REPAIR TABLE table_name;
OPTIMIZE TABLE table_name;

或者是使用`mysqlcheck`工具:

$ mysqlcheck -u root -p --auto-repair --optimize --all-databases

# 其他坑

MySQL表字段字符集不同导致的索引失效问题

# 参考

  • https://medium.com/@adamhooper/in-mysql-never-use-utf8-use-utf8mb4-11761243e434

  • https://dev.mysql.com/doc/refman/8.0/en/charset-unicode-utf8.html

  • https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/

  • https://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci

  • https://mathiasbynens.be/notes/mysql-utf8mb4#utf8-to-utf8mb4

来源:https://blog.liexing.me/2018/07/27/mysql-utf8/

热门内容:你这代码写得真丑,满屏的try-catch,全局异常处理不会吗?
Spring Boot+Redis+拦截器+自定义Annotation实现接口自动幂等SpringBoot+JWT+Shiro+MybatisPlus实现Restful快速开发后端脚手架原创 | Nginx 架构原理科普最近面试BAT,整理一份面试资料《Java面试BAT通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。
获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。
明天见(。・ω・

总结:被MySQL UTF8编码坑的惨痛教训...相关推荐

  1. mysql utf-8不支持生僻字_关于 MySQL UTF8 编码下生僻字符插入失败/假死问题的分析...

    1.问题:mysql 遇到某些中文插入异常 最近有同学反馈了这样一个问题: 上述语句在脚本中 load 入库的时候会 hang 住,web 前端.命令行操作则要么抛出 Incorrect string ...

  2. linux mysql utf-8编码_笔记:linux下mysql设置utf-8编码方法

    一:查看mysql版本 1.1 mysql –V 在终端界面输入上面命令.显示如下: mysql Ver 14.14 Distrib 5.5.35, fordebian-linux-gnu (x86_ ...

  3. mysql 使用真正的utf-8编码

    mysql 使用真正的utf-8编码 create database demo default character set utf8mb4 collate utf8mb4_unicode_ci;

  4. mysql存json将utf8编码 去掉,MySQL对JSON类型UTF-8编码导致中文乱码探讨

    原文:https://www.cnblogs.com/CreateMyself/p/12587426.html 前言 继上文发表之后,结合评论意见并亲自验证最终发现是编码的问题,但是对于字符编码还是有 ...

  5. mysql录入foreigen错误_Python MySQLdb 使用utf-8 编码插入中文数据问题

    最近帮伙计做了一个从网页抓取股票信息并把相应信息存入MySQL中的程序. 使用环境: Python 2.5 for Windows MySQLdb 1.2.2 for Python 2.5 MySQL ...

  6. ssh linux mysql 乱码_JAVA ,SSH中文及其乱码问题的解决 6大配置点 使用UTF-8编码

    JSP,mysql,tomcat下(基于struts2)中文及其乱码问题的解决 6大配置点 使用UTF-8编码 目前对遇到J2EE 开发中 中文及其乱码问题,参考网上资料做个总结, 主要是6大配置点: ...

  7. 修改数据库mysql字符编码为UTF8

    修改数据库mysql字符编码为UTF8 Mysql数据库是一个开源的数据库,应用非常广泛.以下是修改mysql数据库的字符编码的操作过程.步骤1:查看当前的字符编码方法 mysql> show ...

  8. MySQL对JSON类型UTF-8编码导致中文乱码探讨

    继上文发表之后,结合评论意见并亲自验证最终发现是编码的问题,但是对于字符编码还是有点不解,于是乎,有了本文,我们来学习字符编码,在学习的过程中,我发现对于MySQL中JSON类型的编码导致数据中文出现 ...

  9. php mysql 编码为utf-8_php连mysql用 utf-8编码乱码怎么办

    展开全部 PHP页面转UTF-8编码问32313133353236313431303231363533e78988e69d8331333361316639题 1.在代码开始出加入一行: 复制代码 代码 ...

最新文章

  1. 超越YOLOv5,1.3M超轻量,高效易用,目标检测领域这一个就够了!
  2. hexde php_怎样在PHP中把16进制HEX数据转换为2进制数据呢?
  3. 关于使用Windows Live Writer
  4. 线程 、进程、协程 三者区别
  5. ps里面怎么插入流程图_photoshop cs6绘画带箭头简单流程图的操作步骤介绍
  6. ldap的shema
  7. SAP UI5 My Opportunity应用里的 currency validation
  8. MySQL吉连_Learn Jdbc : Java, Jdbc, Odbc
  9. 跑通im2txt 程序(1)
  10. .net中三种Timer使用总结
  11. kubernetes 容器持久化存储PV、PVC、StorageClass
  12. unity button 通过事件改变物体颜色
  13. 烟台蓬莱机场停车费一天多少钱,烟台机场停车哪里便宜
  14. Burp Suite CA证书下载及导入教程
  15. 文档自动同步云服务器,​文件自动同步网盘能实现吗?
  16. T检验、卡方检验以及p-value
  17. 有了这个 Python 库,以后再也不用写正则表达式了
  18. .netframework3.5中TimeZoneInfo 类的使用
  19. 外媒称字节跳动将开发智能手机 官方不予置评
  20. linux中安装卸载命令,Linux软件安装与卸载命令

热门文章

  1. 反射 -- 通过字符串操作对象中的成员
  2. WannaCry的UWP版,哈哈哈
  3. replace 使用函数作为第二参数
  4. linux 下byte,char,unsigned char的区别
  5. 关于C#中编译器保证变量必须初始化规则猜想
  6. 虚函数表剖析,网上转的,呵呵
  7. 【转】Flex4:利用HttpService与ASP.NET传输JSON数据(登录为例)
  8. 【组队学习】【31期】组队学习内容详情
  9. Matlab数据的可视化 -- 条形图
  10. 【Python】序列解包 and * 和 ** 的区别