/ 开发笔记

如何在MySQL中保存emoji表情图标?

在各种社交账号中的昵称中添加表情的人越来越多了。最近我们就遇到过一些奇怪的问题:

  • 比如,游戏排行榜中,有的玩家的名称无法完整显示。
  • 比如,有些玩家报告游戏数据丢失。
  • 等等。
    为什么呢?

在修复了各种逻辑bug以后,仍然有玩家报告诡异的问题,于是,我在日志中添加更加详细的输出信息,然后我就看到了各种表情图标……然后,我发现,这些表情并没有被正确保存到数据库MySql里……

这一刻,我的内心是很无奈的。
然而,
强迫玩家改名是不可能的,
强制删除表情图标是不可取的,
宣布不支持表情图标是不能接受的。

于是我决定研究一下表情图标。我的猜想是:
早期的表情,不管是QQ的,还是一些论坛上的,大多是通过转满实现的,比如 :) 在某些App或者网站上就可能被转义成😊
后来,由于表情图标的使用越来越广泛,于是一个标准的表情库,就因此诞生,这就是emoji。

猜想完毕,我又顺便搜了一下emoji的历史。原来,这些图标,跟我们在QQ或者微信聊天中用到的一些表情最大的不一样是,一个是文本,一个是图片。它们已经是标准的unicode。换句话说,它们已经跟汉语英语一样,是一种语言。

参考:https://emojipedia.org/

现在,大部分的操作系统,包括电脑和移动端,都已经支持显示emoji图标,虽然在不同的平台上稍有不同。这是因为,emoji的编码虽然是标准的,每个表情也是确定的,但是具体的外观,则是又不同的平台来自己实现的,并拥有独立的版权。所以,同样是笑脸,在iOS和Android上是不一样的,在微信和微博上也是不一样的。

https://emojipedia.org/grinning-face/

Snip20180408_1

值得一提的是,
最初的emoji是由日本人Kurita在1999年发明的。
2010年起,emoji被收录到Unicode 6.0标准。
2015年,牛津词典将这个emoji定位年度词汇 => 😂

https://en.wikipedia.org/wiki/Emoji

回到程序上来,既然emoji已经是Unicode文本,那就意味着,我们只需要将它当做正常的文本来处理即可,而怎么显示,则是由更底层的操作系统来实现的。

utf8是最常见的unicode编码。

那么,问题来了,既然,go语言的文本已经是utf8,MySQL的默认编码也已经设置成utf8,那么
为什么我的MySQL里没法存emoji表情呢?

我先用go单独写了一个测试例子,没发现问题。

再搜索一下 MySQL emoji,第一个提示就是 mysql emoji incorrect string value
Snip20180408_3

而搜索结果中stackoverflow第一条就是我遇到的类似问题

https://stackoverflow.com/questions/35125933/mysql-utf8mb4-errors-when-saving-emojis

Snip20180408_4

utf8mb4,进入我的眼帘。这是什么鬼?我之前有幸遇到过一系列的文本编码问题,知道关于Unicode有utf8,utf16,utf32等不同编码,但是这还是第一次遇到utf8mb4编码。

于是乎,我又搜了一下,原来utf8mb4是MySQL自己给自己挖的坑找的一个填补(我脑补的)。

Snip20180408_5

不同于一般的utf8,使用1-4个字节来表示一个unicode字符,MySQL的utf8只使用最多3个字节。于是乎,unicode中4字节和一些特殊字符就没法保存在MySQL里了。

所以,解决方法就是将MySQL数据库的编码改成utf8mb4。
注意,对于已经存在的表,只改变数据库的默认编码是不够的,还需要将这个表的默认编码也改成utf8mb4。
最后,如果这样还不行,将数据库连接串的客户端编码也改成utf8mb4。
这样应该就ok了。