SpringMvc+Hibernate+Mysql保存表情字符(昵称)到数据库报错的问题?
背景:
一个中小型H5游戏
描述:
游戏通过微信授权登入, 获取到用户昵称并将用户信息保存至Mysql数据库, 当遇到有些用户微信昵称中带有表情(特殊字符)时, 保存至数据库出错!
核心错误:
Caused by: java.sql.SQLException: Incorrect string value: '\xF0\x9F\xA4\xB4\xF0\x9F...' for column 'nick_name' at row 7 at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1055) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3536) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3468) at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1957) at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2107) at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2648) at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2086) at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2371) at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2289) at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2274) at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(NewProxyPreparedStatement.java:105) at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2595) ... 77 more
问题剖析:
查阅线上资料后了解到, "特殊表情字符为4个字节,而 utf8 字符集只支持1-3个字节的字符, 将数据库相关字符集改为utf8mb4即可解决问题, 前提是Mysql版本需要5.5以上, 否则不支持该字符集"
修复实践:
第一步: 修改 用户表 > 昵称字段 字符集改为 utf8mb4... 经测试仍无法保存, 报相同错误
第二步: 在以上基础上 修改 用户表 字符集为 utf8mb4...经测试仍旧无法保存, 报相同错误
第三步: 在以上基础上 修改 数据库 字符集为 utf8mb4...经测试仍旧无法保存, 报相同错误
第四步: 在以上基础上 修改Mysql配置文件 my.ini , 修改内容包括: 1. default-character-set=utf8mb4 2. character-set-server=utf8mb4 总之把utf8都改成了 utf8mb4, 重启Mysql服务...经测试该状态下使用Mybatis可以顺利将表情字符存入数据库, 但是使用Hibernate仍旧无法保存, 报相同错误
第五步: 修改项目持久层代码BaseDaoImpl.java, 在插入和修改记录前加入一段代码...经测试, 成功将表情字符存入Mysql
相关代码:
"getSession().connection().prepareStatement("set names utf8mb4").execute();"
public T save(T entity) { Assert.notNull(entity); try { getSession().connection().prepareStatement("set names utf8mb4").execute(); } catch (Exception e) { e.printStackTrace(); } getSession().save(entity); return entity; } public Object update(Object entity) { Assert.notNull(entity); try { getSession().connection().prepareStatement("set names utf8mb4").execute(); } catch (Exception e) { e.printStackTrace(); } getSession().update(entity); //getSession().flush(); return entity; } public Object saveOrUpdate(Object entity) { Assert.notNull(entity); try { getSession().connection().prepareStatement("set names utf8mb4").execute(); } catch (Exception e) { e.printStackTrace(); } getSession().saveOrUpdate(entity); return entity; }