本身的练习项目中涉及保存微信的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的支持,通常可参考以上方法。文章中的关键点也说的比较清楚。html
下面是个人处理方法:
要求:java
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 的问题mysql
保存微信昵称时,Mysql报错。git
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)
报错缘由:github
UTF-8编码有多是两个、三个、四个字节。Emoji表情是4个字节,而Mysql的utf8编码最多3个字节,因此数据插不进去。
网上解决办法:spring
一、修改my.ini [mysqld] character-set-server=utf8mb4在后台配置mysql链接参数中,不要加characterEncoding参数。 不加这个参数时,默认值就时autodetect。将已经建好的表也转换成utf8mb4。命令:(将TABLE_NAME替换成你的表名)sql
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修复。选用另外一种方法。数据库
一、存储nickname的时候,先将nickname用base64编码。我照作之后,发现仍是有问题。最后,使用了一种稍麻烦的办法。segmentfault
String encodeNickname = new String(Base64.getEncoder().encode("Nickname".getBytes()));
二、取出的时候,先将nickname用base64解码。服务器
String decodeNickname = new String(Base64.getDecoder().decode(encodeNickname.getBytes()));
三、数据库中的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一下。
总结:
这是个人一点踩坑经历,但愿能给看到文章的你一点帮助。
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