本文转载自微信公众号《JavaGuide》,作者导哥。转载本文请联系JavaGuide公众号。MySQL字符编码集中有两套UTF-8编码实现:utf8和utf8mb4。如果使用utf8,在存储emoji符号和一些繁体字和繁体字时会出现错误。为什么会这样?本文可以从源头上给你答案。什么是字符集?字符是各种字符和符号的总称,包括各国字符、标点符号、表情符号、数字等。字符集是字符的集合。字符集的种类很多,每一种字符集所能表示的字符范围通常是不同的。例如,某些字符集不能表示汉字。计算机只能存储二进制数据,那么英文、汉字、表情符号等字符应该如何存储呢?我们需要将这些字符与二进制系统数据一一匹配。例如字符“a”对应“01100001”,反之亦然。“01100001”对应“a”。我们将二进制数据对应字符的过程称为“字符编码”,反过来,将二进制数据解析为字符的过程称为“字符解码”。常见的字符集有哪些?常见的字符集有ASCII、GB2312、GBK、UTF-8....不同字符集的主要区别是:可以表示的字符范围编码方式ASCIIASCII(AmericanStandardCodeforInformationInterchange,美国标准码forInformationInterchange)是一组主要用于现代美式英语的字符集(这也是ASCII字符集的局限性)。为什么ASCII字符集没有考虑其他字符,例如中文?因为计算机是美国人发明的。当时计算机的发展还处于起步阶段,在其他国家还没有大规模使用。因此,美国在发布ASCII字符集时,并没有考虑与其他国家语言的兼容性。ASCII字符集至今共定义了128个字符,其中33个控制字符(如回车、删除)不能显示。ASCII码的长度为一个字节,即8位。例如“a”对应的ASCII码为“01100001”。但是最高位0只作为校验位,其余7位由0和1组合而成,所以ASCII字符集可以定义128(2^7)个字符。因为能用ASCII码表示的字符太少了。后来人们对其进行了扩展,得到了ASCII扩展字符集。ASCII扩展字符集使用8位来表示一个字符,所以ASCII扩展字符集可以定义256(2^8)个字符。ASCII字符编码GB2312上面我们说过,ASCII字符集是适合现代美式英语的字符集。因此,很多国家都在摸索一套适合自己国家语言的字符集。GB2312字符集是对汉字友好的字符集。收录汉字6700多个,基本涵盖了大部分常用汉字。但是GB2312字符集不支持大部分的生僻字和繁体字。对于英文字符,GB2312编码和ASCII编码是一样的,1字节编码就够了。对于非英文字符,需要2字节编码。GBKGBK字符集可以看作是GB2312字符集的扩展,兼容GB2312字符集,包含20000多个汉字。GBK中的K是汉语拼音KuoZhan(扩展)中“Kuo”的首字母。GB18030GB18030完全兼容GB2312和GBK字符集。它包括中国少数民族的文字,包括日本和韩国的汉字。它是迄今为止最全面的汉字集,共有7万多个汉字。BIG5BIG5主要针对繁体中文,包含13000多个汉字。为了更适合本国语言,Unicode&UTF-8编码产生了很多字符集。上面我们也说过,不同的字符集和编码规则可以表示的字符范围是有区别的。这就导致了一个很严重的问题:使用错误的编码方式查看包含字符的文件会产生乱码。比如用UTF-8编码打开GB2312编码格式的文件,就会出现乱码。例:汉字“牛”的GB2312编码十六进制值为“C5A3”,但“C5A3”为“?”使用UTF-8解码后。可以通过这个网站在线编解码:https://www.haomeili.net/HanZi/ZiFuBianMaZhuanHuan让我们了解乱码的本质:使用不同或不兼容的字符集进行编解码。为了解决这个问题,人们想:“要是能有一个包含世界上所有字符的字符集就好了!”。于是,Unicode就带着这个使命诞生了。Unicode字符集包含了世界上几乎所有已知的字符。但是Unicode字符集并没有规定如何存储这些字符(即如何用二进制数据来表示这些字符)。然后,就是UTF-8(8位Unicode转换格式)。类似的还有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是目前使用最广泛的字符编码。MySQL字符集MySQL支持UTF-8、GB2312、GBK、BIG5等多种字符编码方式。您可以使用SHOWCHARSET命令查看它。通常,我们建议使用UTF-8作为默认字符编码。不过,这里有个小坑。MySQL字符编码集中有两套UTF-8编码实现:utf8:utf8编码只支持1-3个字节。在utf8编码中,中文占3个字节,其他数字、英文、符号占1个字节。但是emoji符号占用4个字节,一些比较复杂的字符和繁体字也占用4个字节。utf8mb4:完整的UTF-8实现,正版!它最多支持4个字节来表示字符,因此可以用来存储emoji符号。为什么会有两套UTF-8编码实现?原因如下:因此,如果需要将emoji类型的数据或一些复杂的文本或繁体字存储到MySQL数据库中,数据库编码必须指定为utf8mb4,而不是utf8。否则存储时会报错。让我们演示一下!(环境:MySQL5.7+)建表语句如下,我们指定数据库CHARSET为utf8。CREATETABLE`user`(`id`varchar(66)CHARACTERSETutf8mb4NOTNULL,`name`varchar(33)CHARACTERSETutf8mb4NOTNULL,`phone`varchar(33)CHARACTERSETutf8mb4DEFAULTNULL,`password`varchar(100)CHARACTERSETutf8mb4DEFAULTNULL)ENGINE=InnoDB当插入语句如下向数据库中插入数据,报错!INSERTINTO`user`(`id`,`name`,`phone`,`password`)VALUES('A00003','导哥😘😘😘','181631312312','123456');报错信息如下:Incorrectstringvalue:'\xF0\x9F\x98\x98\xF0\x9F...'forcolumn'name'atrow1参考字符集和字符编码(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/UnicodeGB2312-维基百科:https://zh.wikipedia.org/wiki/GB_2312UTF-8-维基百科:https://zh.wikipedia.org/wiki/UTF-8GB18030-维基百科:https://zh.wikipedia.org/wiki/GB_18030
