那天,我还在外面吃成都六姐的冒菜。

牛肉丸裹上麻酱后,狠狠嘬一口,都要入嘴了。

产品经理突然发来消息。

"线上有些用户不能注册了"

心想着"关我x事,又不是我做的模块",放下手机。

不对,那老哥上礼拜刚离职了,想到这里,夹住毛肚的手微微颤抖

对面继续发:"还有些用户不能改名"

"如果用上表情符号的话,问题必现"

可以了,这下问题几乎直接定位了。

危,速归。

有经验的兄弟们很容易看出,这肯定是因为字符集的缘故。

复现问题

我们来简单复现下这个问题。

如果你有一张数据库表,建表sql就像下面一样。

建表sql语句

接下来如果你插入的数据是

insert成功case

能成功。一切正常。

但如果你插入的是

insert失败case

就会报错

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

区别在于后者多了个emoji表情。

明明也是字符串,为什么字符串里含有emoji表情,插入就会报错呢?

我们从字符集编码这个话题开始聊起。

编码和字符集的关系

虽然我们平时可以在编辑器上输入各种中文英文字母,但这些都是给人读的,不是给计算机读的,其实计算机真正保存和传输数据都是以二进制0101的格式进行的。

那么就需要有一个规则,把中文和英文字母转化为二进制,比如"debug",计算机就需要把它转化为下图这样。

debug的编码

其中d对应十六进制下的64,它可以转换为01二进制的格式。

于是字母和数字就这样一一对应起来了,这就是ASCII编码格式。

它用一个字节,也就是8位来标识字符,基础符号有128个,扩展符号也是128个。

也就只能表示下英文字母和数字

这哪里够用。

塞牙缝都不够。

于是为了标识中文,出现了GB2312的编码格式。为了标识希腊语,出现了greek编码格式,为了标识俄语,整了cp866编码格式。

这百花齐放的场面,显然不是一个爱写if else的程序员想看到的。

为了统一它们,于是出现了Unicode编码格式,它用了2~4个字节来表示字符,这样理论上所有符号都能被收录进去,并且它还完全兼容ASCII的编码,也就是说,同样是字母d,在ASCII用64表示,在Unicode里还是用64来表示。

不同的地方是ASCII编码用1个字节来表示,而Unicode用则两个字节来表示。

比如下图,同样都是字母d,unicode比ascii多使用了一个字节。

unicode比ascii多使用一个字节

我们可以注意到,上面的unicode编码,放在前面的都是0,其实用不上,但还占了个字节,有点浪费,完全能隐藏掉。如果我们能做到该隐藏时隐藏,这样就能省下不少空间,按这个思路,就是就有了UTF-8编码

编码格式

来总结下。

按照一定规则把符号和二进制码对应起来,这就是编码。而把n多这种已经编码的字符聚在一起,就是我们常说的字符集

比如utf-8字符集就是所有utf-8编码格式的字符的合集。

字符和字符集的关系

mysql的字符集

想看下mysql支持哪些字符集。可以执行 show charset;

数据库支持哪些字符集

上面这么多字符集,我们只需要关注utf8和utf8mb4就够了。

utf8和utf8mb4的区别

上面提到utf-8是在unicode的基础上做的优化,既然unicode有办法表示所有字符,那utf-8也一样可以表示所有字符,为了避免混淆,我在后面叫它大utf8

而从上面mysql支持的字符集的图里,我们看到了utf8和utf8mb4。

先说utf8mb4编码,mb4就是most bytes 4的意思,从上图最右边的Maxlen可以看到,它最大支持用4个字节来表示字符,它几乎可以用来表示目前已知的所有的字符。

再说mysql字符集里的utf8,它是数据库的默认字符集。但注意,此utf8非彼utf8,我们叫它小utf8字符集。为什么这么说,因为从Maxlen可以看出,它最多支持用3个字节去表示字符,按utf8mb4的命名方式,准确点应该叫它utf8mb3

不好意思,有被严谨到的兄弟们,评论区扣个"严谨"。

它就像是阉割版的utf8mb4,只支持部分字符。比如emoji表情,它就不支持。

utf8mb3和utf8mb4的关系

而mysql支持的字符集里,第三列,collation,它是指字符集的比较规则

比如,"debug"和"Debug"是同一个单词,但它们大小写不同,该不该判为同一个单词呢。

这时候就需要用到collation了。

通过SHOW COLLATION WHERE Charset = 'utf8mb4';可以查看到utf8mb4下支持什么比较规则。

utf8mb4字符集比较规则

如果collation = utf8mb4_general_ci,是指使用utf8mb4字符集的前提下,挨个字符进行比较general),并且不区分大小写(_ci,case insensitice)。

这种情况下,"debug"和"Debug"是同一个单词

对比规则-大小写不敏感

如果改成collation=utf8mb4_bin,就是指挨个比较二进制位大小

于是"debug"和"Debug"就不是同一个单词。

对比规则-大小写敏感

那utf8mb4对比utf8mb3有什么劣势吗?

我们知道数据库表里,字段类型如果是char(2)的话,里面的2是指字符个数,也就是说不管这张表用的是什么编码的字符集,都能放上2个字符。

而char又是固定长度,为了能放下2个utf8mb4的字符,char会默认保留2*4(maxlen=4)= 8个字节的空间。

如果是utf8mb3,则会默认保留 2 * 3 (maxlen=3) = 6个字节的空间。也就是说,在这种情况下,utf8mb4会比utf8mb3多使用一些空间。

但这真的无关紧要,如果我不用char,用varchar就好了,varchar不是固定长度,也就没有上面这些麻烦事了。

所以我个人认为,utf8mb4比起 utf8mb3 几乎没有劣势。

如何查看数据库表的字符集

如果我们不知道自己的表是用的哪种字符集,可以通过下面的方式进行查看。

查看数据库表的字符集

再看报错原因

到这里,我们回到文章开头的问题。

因为数据库表在建表的时候使用 DEFAULT CHARSET=utf8, 相当于指定了utf8mb3字符集格式。

而在执行insert数据的时候,又不讲武德,加入了emoji表情这种utf8mb4才能支持的字符,mysql识别到这是utf8mb3不支持的字符,于是忍痛报错。

要修复也很简单,执行下面的sql语句,就可以把数据库表的字符集改成utf8mb4

ALTER TABLE user CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

答应我,以后建表,我们都无脑选utf8mb4。

选utf8除了在char字段场景下会比utf8mb4稍微省一点空间外,几乎没任何好处。

这点空间省下来了能提高你的绩效吗?不能。

但如果因此炸雷了,那你号就没了。

总结

  • ASCII编码支持数字和字母。大佬们为了支持中文引入了GB2312编码格式,其他国家的大佬们为了支持更多语言和符号,也引入了相应的编码格式。为了统一这些各种编码格式,大佬们又引入了unicode编码格式,而utf-8则在unicode的基础上做了优化,压缩了空间。

  • mysql默认的utf8字符集,其实只是utf8mb3,并不完整,当插入emoji表情等特殊字符时,会报错,导致插入、更新数据失败。改成utf8mb4就好了,它能支持更多字符。

  • mysql建表时如果不知道该选什么字符集,无脑选utf8mb4就行了,你会感谢我的。

mysql插入数据会失败?为什么?相关推荐

  1. c# 向mysql插入数据_C#连接mysql数据库 及向表中插入数据的方法

    mysql 语句操作: 创建数据库:create database hotelATMDb; use hotelATMDb; C#连接mysql 1.引用 dll MySql.Data.dll 下载地址 ...

  2. 七种MYSQL插入数据后返回自增主键ID的方法

    我们都知道,mysql中的insert插入之后会有返回值,返回的是影响的行数,也就是说,成功插入一条数据之后返回的是1,失败则返回0.那么,很多时候我们都想要得到最后插入的id值,下面七种方法均可,结 ...

  3. PHP MySQL 插入数据

    使用 MySQLi 和 PDO 向 MySQL 插入数据 在创建完数据库和表后,我们可以向表中添加数据. 以下为一些语法规则: PHP 中 SQL 查询语句必须使用引号 在 SQL 查询语句中的字符串 ...

  4. python操作mysql插入数据

    python操作mysql插入数据 首先安装pymysql这个库 pycharm连接数据库 操作mysql语句 连接数据库 插入数据 由于有时候,数据存在excel表格中,需要借助python去读取数 ...

  5. MySQL 插入数据时,中文乱码问题的解决

    MySQL 插入数据时,中文乱码问题的解决 参考文章: (1)MySQL 插入数据时,中文乱码问题的解决 (2)https://www.cnblogs.com/sunzn/archive/2013/0 ...

  6. linux mysql插入中文乱码_解决Linux下Tomcat向MySQL插入数据中文乱码问题

    一.问题 在windows上面使用eclipse开发的项目在windows上面运行一切正常,部署到腾讯云时出现向MySQL数据库中插入数据是中文乱码 二.解决办法 1.尝试一 直接在linux上面使用 ...

  7. mysql插入数据与删除重复记录的几个例子(收藏)

    mysql插入数据与删除重复记录的几个例子 12-26shell脚本实现mysql数据的批量插入 12-26mysql循环语句插入数据的例子 12-26mysql批量插入数据(insert into ...

  8. mysql c接口返回自增id_详解mysql插入数据后返回自增ID的七种方法

    引言 mysql 和 oracle 插入的时候有一个很大的区别是: oracle 支持序列做 id: mysql 本身有一个列可以做自增长字段. mysql 在插入一条数据后,如何能获得到这个自增 i ...

  9. java mysql 插入 乱码_java向mysql插入数据乱码问题的解决方法

    遇到java向mysql插入数据乱码问题,如何解决? MySQL默认编码是latin1 mysql> show variables like 'character%'; +----------- ...

最新文章

  1. activeMQ 本地测试
  2. 处理字符串时常用方法0914
  3. ADAS辅助驾驶_自动驾驶_技术点列表
  4. java label api_使用python API进行的培训作为Java API中LabelImage模块的输入?
  5. 现在的网管都在做什么!
  6. linux x86-64下,Linux x86_64下安装Flash Player 9
  7. 缓存系列之二:CDN与其他层面缓存
  8. 网易云音乐被纳入港股通 3月7日起生效
  9. solr集成IKAnalyzer中文分词器
  10. ext数据库读取动态添加window组件
  11. 计算机虚拟技术有那么难吗,价值在哪里?
  12. 抖音文案、声音、设计、视频、图片素材网站
  13. 2021“中兴捧月“图灵赛道总结
  14. 【微信小程序】微信公众平台合法域名设置
  15. linux下的时间 date 和 hwclock命令
  16. luogu4182 [USACO18JAN] Lifeguards P (单调队列优化dp)
  17. panic: runtime error: invalid memory address or nil pointer dereference
  18. POS机刷卡跨行交易的清算方式
  19. 【干货书】分布式算法
  20. 有哪些适合在家做的正规兼职工作

热门文章

  1. 信息安全框架——三个方面
  2. 计算机网络各层协议说明及常见协议
  3. CAS机制以及简单实现
  4. MySQL数据库基本管理
  5. jq将数据库数据显示在select标签上
  6. vue——双层循环嵌套
  7. Linux从入门到精通——基本命令
  8. 如何在云计算平台上完成分子对接
  9. iPhone X适配 最简单粗暴的
  10. JavaScript期末大作业 罗兰永恒花园动漫价绍网页 7页,含有table表格,js表单验证还有首页视频