文档章节

微信nickname乱码(emoji)及mysql编码格式设置(utf8mb4)解决的过程

Jack088
 Jack088
发布于 05/16 16:46
字数 1908
阅读 135
收藏 3
自己的练习项目中涉及保存微信的nickname,之前一直正常使用,但是突然遇到一个之前没有遇到的问题。经过调试发现错误如下:

Incorrect string value: '\xF0\x9F\x99\x88\xF0\x9F...' for column 'nickname' at row 1
经过仔细查看发现可以获得nickname的数据,但是无法保存到mysql数据库,查看用户的微信发现在nickname中使用了emoji字符。
到百度(只能用这个,其他的麻烦呀。)上查找发现主要解决方案就是MySQL的编码设置由utf8转为utf8mb4。
具体解释可见:[详细emoji表情与utf8mb4的关系][1] ,写的非常全面详细。

网上的解决办法大多是修改my.cnf参数,设置mysql的编码为utf8mb4,这种方法虽然彻底,但是通常要重启mysql,会造成生产系统临时当机。我认为写的比较好的方法是:mysql/Java服务端对emoji的支持,一般可参考以上方法。文章中的关键点也说的比较清楚。

下面是我的处理方法:
要求:

1.MySQL的版本不能太低,低于5.5.3的版本不支持utf8mb4编码。select version();
2.JDBC驱动版本不能太低,mysql connector版本高于5.1.13。
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.38</version>
</dependency>

3.将表中的对应字段,比如会员表的呢称字段,其字符集修改成utf8mb4。
4.最后修改druid数据源的配置,增加一行:


<property name="connectionInitSqls" value="set names utf8mb4;"/>

5.检查下jdbc连接串的设置:

jdbc:mysql://localhost:3306/dbname?useUnicode=true&characterEncoding=utf8

这里要注意:有人建议删除useUnicode=true&characterEncoding=utf8,但好像我这里会发生保存数据时发生乱码的现象。

本文重要参考:mysql : utf8mb4 的问题

 

JAVA解决Emoji表情存储至Mysql报错问题

保存微信昵称时,Mysql报错。

复制代码

Caused by: java.sql.SQLException: Incorrect string value: '\xF0\x9F\x98...' for column 'nick_name' at row 1
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1074)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4096)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4028)
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2490)
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2651)
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2734)
    at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2155)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2458)

复制代码

报错原因:

UTF-8编码有可能是两个、三个、四个字节。Emoji表情是4个字节,而Mysql的utf8编码最多3个字节,所以数据插不进去。

 

网上解决办法:

1、修改my.ini [mysqld] character-set-server=utf8mb4在后台配置mysql连接参数中,不要加characterEncoding参数。 不加这个参数时,默认值就时autodetect。将已经建好的表也转换成utf8mb4。命令:(将TABLE_NAME替换成你的表名)

ALTER TABLE `TABLE_NAME` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
将需要使用emoji的字段设置类型为utf8mb4_general_ci:
ALTER TABLE `TABLE_NAME`MODIFY COLUMN `COLUMN_NAME`  text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

 

照做之后,发现并没有解决问题。找不到原因。等以后空闲时间慢慢调错。先将这次BUG修复。选用另一种方法。

1、存储nickname的时候,先将nickname用base64编码。我照做以后,发现还是有问题。最后,使用了一种稍麻烦的办法。

String encodeNickname = new String(Base64.getEncoder().encode("Nickname".getBytes()));

2、取出的时候,先将nickname用base64解码。

String decodeNickname = new String(Base64.getDecoder().decode(encodeNickname.getBytes()));

3、数据库中的nickname手动用base64编码更新。

 

结束上述步骤后,查看后台发现傻了眼。新增的用户nickname可以正常显示emoji表情了。但是之前手动编码的nickname全部乱码了。

没有找到原因。以为是没有加上编码格式的原因。更改代码:

String encodeNickname = new String (Base64.getEncoder().encode("Nickname".getBytes()),"utf-8");
System.out.println("编码后:"+encodeNickname);
String decodeNickname = new String (Base64.getDecoder().decode(encodeNickname.getBytes()),"utf-8");
System.out.println("解码后:"+decodeNickname);

还是乱码!百思不得其解。福至心灵,拿gbk将之前编码的数据解码试了下。发现显示正常了。

new String (Base64.getDecoder().decode(encodeNickname.getBytes()),"gbk");

重新把之前nickname用gbk解码获取用户昵称,然后用utf-8编码存储,utf-8解码。一切正常了。

 

记一次生产事故踩坑。血淋淋的惨痛教训

众所周知 mysql 存 emoji 表情要用 utf8mb4 这个字符集

OK 没问题,设置 nick_name 为 utf8mb4 varchar(50)

测试的结果:

    emoji 表情储存成功

没有问题  完全oj8k  发生产!

微信公众号做了推送,为了抗住流量,还准备了100台服务器。

晚上监控流量,服务器各项指标正常。

但是一看日志,发现日志疯狂报错:部分敏感信息及参数已删除

exception[order=UserInfoRequestType{activityId=, uid=, nickName=wing.?, headImgUrl=}]
org.springframework.jdbc.UncategorizedSQLException: 
### Error updating database.  Cause: java.sql.SQLException: Incorrect string value: '\xF0\x9F\x90\x9D' for column 'nick_name' at row 1
### The error occurred while setting parameters
### SQL: insert into s_user_info         (id,nick_name,uid,support_detail,popularity,img_url,DataChange_CreateTime,DataChange_LastTime,activity_id)         values (?, ?, ?,         ?, ?, ?,         ?,?,?)
### Cause: java.sql.SQLException: Incorrect string value: '\xF0\x9F\x90\x9D' for column 'nick_name' at row 1
; uncategorized SQLException for SQL []; SQL state [HY000]; error code [1366]; Incorrect string value: '\xF0\x9F\x90\x9D' for column 'nick_name' at row 1; nested exception is java.sql.SQLException: Incorrect string value: '\xF0\x9F\x90\x9D' for column 'nick_name' at row 1   at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:84)

看到一堆的报错,马上就慌了。

nick_name 存不进去,仔细调研发现是 部分emoji表情的用户 的 昵称储存失败。OK,马上fixbug,字符串存不了,我转base64总可以了吧,改完发测试环境,测试测了这个接口没有问题,又发生产,结果引起了另外一个接口的报错,瞬间又是一堆错误日志,整个人瞬间斯巴达了 emmm......  于是马上回退到上一个版本,让部分特殊emoji表情的用户无法活动。再继续fixbug。

现在库里既有base64的昵称 也有未 base64 的昵称 。真是让人头大。

经过周末两天的加班,终于把这个问题稳定的解决了:

数据库存 base64 encode 的 昵称, 从DB取出来时  decode一下。

总结:

  • 1、我设置了utf8mb4 还是无法储存部分 moji 表情的原因是:新的moji 表情越来越多,mysql 版本却没有跟上,导致新的moji 表情存不进去。
  • 2、mysql 存 moji 表情 不要完全依赖 utf8mb4这个字符集来帮你处理 , 可以就选用utf8 长度给长一点 转 base64 后存,取的时候再转成字符串就行,当然转base64 的 encode  和 decode 操作都会消耗你 CPU 的 性能,在高并发场景下要多测试,然后进行方案的取舍。
  • 3、在GitHub上找到 emoji-java 这个来解决,下次我应该就会用这个来处理emoji表情了。
  • 4、就算是高并发场景,遇到生产环境大量报错不要慌,不要急,要稳住心态,只要一些硬性指标(比如订单量)没有下降就还能撑住。
  • 5、学会批判的看事情,百度得到的答案不一定对,相信很多人遇到要存moji 表情 都是 直接谷歌或是百度 mysql 如何存 emoji表情,然后看到一堆文章,找了篇看起来很多的,就拿着参考开始实践了。我们还需要站到对立面多思考一个问题:Emoji表情存储至Mysql报错问题,于是你就能找到这篇:JAVA解决Emoji表情存储至Mysql报错问题 就不会踩坑了

这是我的一点踩坑经历,希望能给看到文章的你一点帮助。

 

ps:

https://segmentfault.com/a/1190000004594385?utm_medium=referral&utm_source=tuicool

https://www.cnblogs.com/yugure/articles/7773013.html

https://cloud.tencent.com/developer/article/1393147

本文转载自:https://segmentfault.com/a/1190000004594385?utm_medium=referral&utm_source=tuicool

Jack088
粉丝 45
博文 562
码字总数 90026
作品 0
扬州
程序员
私信 提问
JDBC对Mysql utf8mb4字符集的处理

在开发微信开放平台, 接入微信公众号的数据时, 关于用户的nickname和文本消息是,大量出现emoji的文本信息, 超时了utf-8字符集的存储范围 在存储数据时, 出现部分特殊字符存储字符串失败. 服务...

alamongo
2018/01/05
0
0
spring,web,java 开发中乱码解决方案

修改HTML/JSP页面编码格式: 或<%@ page contentType="text/html; charset=UTF-8"%> web.xml中的编码设置( 需要设置forceEncoding参数值为true,强制以目标编码为编码格式 ) CharacterEncodin......

ybyron
2017/06/26
0
0
Laravel项目中使用mysql存储emoji表情乱码的问题

在mysql中存储中文时通常用UTF8的编码方式,而用此编码方式存储emoji表情时,会出现乱码或插入失败,原因是utf8编码部支持emoji表情,至于为什么不支持,可参考这篇文章:mysql utf8mb4与emo...

4fun
2016/08/03
488
9
Jade插入emoji字符总结

不修改Mysql 服务器字符集(charactersetserver=utf8mb4)的前提下,使用Jade插入Emoji字符. Mysql服务器字符集设置: mysql> show variables like 'character%';+-------------------------......

zgw06629
2015/05/05
1K
0
mysql保存emoji表情(微信昵称),使用utf8mb4格式保存微信昵称

SHOW VARIABLES WHERE Variablename LIKE 'characterset%' OR Variablename LIKE 'collation%'; 查询字符集 SET NAMES utf8mb4; 将当前连接的数据格式设置为utf8mb4,这时候当前连接才能保存......

花树堆雪
09/04
52
0

没有更多内容

加载失败,请刷新页面

加载更多

CSS--列表

一、列表标识项 list-style-type none:去掉标识项 disc:默认实心圆 circle:空心圆 squire:矩形 二、列表项图片 list-style-img: 取值:url(路径) 三、列表项位置 list-style-position:...

wytao1995
今天
6
0
linux 命令-文本比较comm、diff、patch

本文原创首发于公众号:编程三分钟 今天学了三个文本比较的命令分享给大家。 comm comm 命令比较相同的文本 $ cat charabc$ cat chardiffadc 比如,我有两个文件char和chardiff如上,...

编程三分钟
今天
7
0
QML教程

https://blog.csdn.net/qq_40194498/article/category/7580030 https://blog.csdn.net/LaineGates/article/details/50887765...

shzwork
今天
5
0
HA Cluster之5

对于使用heartbeat v2版的CRM配置的集群信息都是保存在一个名为cib.xml的配置文件中,存放在/var/lib/heartbeat/crm/下。CIB:Cluster Information Base,由于xml文件配置不是那么方便,所以...

lhdzw
今天
6
0
玩转Redis-Redis基础数据结构及核心命令

  《玩转Redis》系列文章主要讲述Redis的基础及中高级应用,文章基于Redis5.0.4+。本文主要讲述Redis的数据结构String,《玩转Redis-Redis基础数据结构及核心命令》相关操作命令为方便对比...

zxiaofan666
今天
11
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部