前提
这次仍然是在我的日报系统上遇到的异常崩溃,关于日报系统的简要说明请参阅《记一次重构》.
异常信息
Incorrect string value: ‘\xF0\x9F\x8C\xB8’ for column ‘Content’ at row 49
就是说在第49
行的Content
这一列插入了不正确的字符串值\xF0\x9F\x8C\xB8
。
问题所在
这个问题倒是很好查,看来很多人都遇到过。简而言之,问题在于向数据库中插入了emoji表情。
然而问题并不是下面这种图片格式的Emoji造成的:
因为我在解析HTML时会过滤掉<img>标签。
又经过一番搜索和验证,我发现了如下图的这种东西:
表面上看,只是和上面的Emoji风格不同,实际上另有玄机!!!
真相——文本格式的Emoji
我从网站上复制了这些Emoji的一部分放到文本文档里,想看看这些东西是不是图片(图片是不能复制进文本文档的),结果看到了惊掉下巴的东西:
没错,这些是上述那些看似彩色图片的Emoji的真身,文本格式。
原因
那么,既然这种东西也算是一个一个的字符,为什么会出现数据库插入异常呢?
原因在于:
普通的字符串或者表情都是占位
3
个字节,所以utf8
足够用了,但是移动端的表情符号占位是4
个字节,普通的utf8
就不够用了,为了应对无线互联网的机遇和挑战、避免 emoji 表情符号带来的问题、涉及无线相关的 MySQL 数据库建议都提前采用utf8mb4
字符集,这必须要作为移动互联网行业的一个技术选型的要点。[1]
总之,这种字符存在于扩展之后的每个字符占4个字节的utf8mb4字符集中,转换为每个字符为3个字节的utf8就出错了。
关于utf8mb4,请移步《浅谈MySQL中utf8和utf8mb4的区别》
解决方案
根据查到的解决方案,亲测有效但是描述上有错误,我再赘述一下。
第一步——修改MySQL配置
①打开mysql的配置文件,windows下的为my.ini(linux下的为my.cnf);
②找到[client]
,在下面添加一行
default-character-set = utf8mb4
③找到[mysqld]
,在下面添加两行
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
④找到[mysql]
,在下面添加一行
default-character-set = utf8mb4
特别要注意的是,小心不要把这些写在以#
开头的注释里。
第二步——修改字段的字符集
在数据库中,修改相应字段(我这里是text类型的Content字段)的字符集为utf8mb4
,排序规则为utf8mb4_general_ci
。
第三步——修改代码中数据库连接字符串
去掉数据库连接字符串中的?characterEncoding=utf-8
因为怕出现汉字乱码的问题,我就没有做这一步试了一下,亲测是可以的。因此这一步不像网上说的必须要做,视情况而定。
后记
后来查明,是一位同学的日报中出现了这个:
我问他的时候,他自己都没有意识到发了这个东西过来。可能是误触了输入法提供的这个吧。