当前位置: 首页 > 科技观察

MySQL会不会插入数据失败?为什么?

时间:2023-03-12 07:40:32 科技观察

那天还在外面吃着成都六姐的冒菜。将牛肉丸裹上麻酱后,用力喝了一口,差点掉进嘴里。产品经理突然发来消息。“部分在线用户无法注册”。心想“关我什么事,又不是我做的模组”,放下了电话。不,那个老人上周刚离职。想到这里,捂着肚子的手微微颤抖了一下。对面继续发帖:“还有部分用户无法改名。”“如果使用表情符号,就会出现问题。”好了,现在问题差不多直接定位了。危险,速回。有经验的兄弟很容易看出,这一定是字符集的原因。重现问题我们简单的重现一下这个问题。如果您有数据库表,请按如下方式创建表sql。建表sql语句接下来如果你插入的数据是.insert成功,case成功。一切正常。但是如果插入insertfailurecase,就会报错。Incorrectstringvalue:'\xF0\x9F\x98\x81'forcolumn'name'atrow1区别在于后者多了一个emoji表情。明明也是字符串,为什么字符串中包含emoji表情,插入时会报错呢?我们先从字符集编码的话题说起。编码与字符集的关系虽然我们平时可以在编辑器上输入各种中英文字母,但这些都是给人看的,不是给电脑看的。事实上,计算机实际上是以二进制0101格式保存和传输数据的。然后需要有一个规则将中英文字母转换成二进制,比如“debug”,需要计算机将其转换成下图。在debug的编码中,d对应十六进制的64,可以转化为01的二进制格式。所以字母和数字一一对应,就是ASCII编码格式。它使用一个字节,即8位,来标识字符。有128个基本符号和128个扩展符号。只能表示英文字母和数字。这还不够。牙缝不够。于是为了识别中文,出现了GB2312的编码格式。为了识别希腊语,出现了希腊编码格式,为了识别俄语,调整了cp866编码格式。这种百花齐放的景象,显然不是一个爱写ifelse的程序员愿意看到的。为了统一它们,出现了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支持哪些字符集。您可以执行显示字符集。数据库支持哪些字符集?上面这么多字符集,我们只需要关注utf8和utf8mb4即可。utf8和utf8mb4的区别上面说了utf-8是在unicode的基础上优化的。既然unicode有办法表示所有的字符,那么utf-8也可以表示所有的字符。为了避免混淆,后面就叫bigutf8。从上图mysql支持的字符集可以看出utf8和utf8mb4。先说utf8mb4编码。mb4表示mostbytes4,从上图最右边的Maxlen可以看出,它最多支持4个字节来表示字符,几乎可以用来表示目前已知的所有字符。先说mysql字符集中的utf8,这是数据库默认的字符集。但是注意这个utf8不是那个utf8,我们称之为小utf8字符集。为什么这么说呢,因为从Maxlen可以看出它最多支持3个字节来表示字符。按照utf8mb4的命名方式,准确的说应该叫utf8mb3。不好意思,一直严谨的兄弟们,请在评论区标注“严谨”。它就像一个阉割版的utf8mb4,只支持部分字符。比如emoji表情,不支持。utf8mb3和utf8mb4的关系在mysql支持的字符集中,第三列collat??ion是指字符集的比较规则。例如,“debug”和“Debug”是同一个词,只是大小写不同。他们应该被判断为同一个词吗?这时候就需要整理了。通过SHOWCOLLATIONWHERECharset='utf8mb4';你可以查看utf8mb4下支持哪些比较规则。utf8mb4字符集比较规则如果collat??ion=utf8mb4_general_ci,表示在使用utf8mb4字符集的前提下,一一比较(general),不区分大小写(_ci,不区分大小写)。在这种情况下,“调试”和“调试”是同一个词。比较规则-不区分大小写如果改为collat??ion=utf8mb4_bin,则表示一位一位比较二进制位的大小。所以“调试”和“调试”不是同一个词。比较规则-区分大小写,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几乎没有缺点。如何查看数据库表的字符集如果我们不知道我们的表使用的是哪种字符集,可以通过以下方式查看。检查数据库表的字符集再看错误原因至此,我们回到文章开头的问题。因为数据库表在建表时使用了DEFAULTCHARSET=utf8,相当于指定了utf8mb3字符集格式。执行insert数据的时候,不讲武功,加了emoji这个只有utf8mb4才能支持的字符。mysql识别到这是utf8mb3不支持的字符,于是无奈报错。修复也很简单,执行下面的sql语句,将数据库表的字符集改为utf8mb4即可。ALTERTABLEuserCONVERTTOCHARACTERSETutf8mb4COLLATEutf8mb4_general_ci;答应我,以后建表的时候不假思索就选择utf8mb4。选择utf8除了在char字段场景下会比utf8mb4节省一点空间外,几乎没有任何好处。节省这么小的空间会提高你的表现吗?没有。但是如果因为这个爆了,那你的账号就没了。总结ASCII编码支持数字和字母。大佬们为了支持中文引入了GB2312编码格式,其他国家的大佬们为了支持更多的语言和符号也引入了相应的编码格式。为了统一这几种编码格式,大佬们推出了unicode编码格式,utf-8在unicode的基础上进行了优化,压缩了空间。mysql默认的utf8字符集其实只有utf8mb3,并不完整。在插入emoji表情等特殊字符时,会报错,导致无法插入和更新数据。改成utf8mb4就可以了,可以支持更多的字符。如果你在mysql建表的时候不知道选择什么字符集,想都没想就选utf8mb4,你会感谢我的。最后A同学本来这张表设计的很简单,也有字符串类型的字段,但是字段的含义决定了不会有奇怪的字符。使用utf8比较合理,节省空间。后来交给了B同学,B同学在这个基础上加了很多字段。幸运的是,姓名字段是辞职前最后需要添加的字段。终于到我了。何等的鼓声和雷声。哦,什么。那么问题来了。这样的意外,一旦开replaymeeting,要停多少P?