上周在做微信摄影投票时,遇到这么一个情况,在微信中,如果将用户昵称修改为Emoji表情字符后,再通过hibernate向MySQL存储时,报如下错误:
java.sql.SQLException: Incorrect string value: '\xF0\x9F\x92\x94' for column 'name' at row 1
at com..jdbc.SQLError.createSQLException(SQLError.java:1073)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3593)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3525)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1986)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2140)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2620)
at com.mysql.jdbc.StatementImpl.executeUpdate(StatementImpl.java:1662)
at com.mysql.jdbc.StatementImpl.executeUpdate(StatementImpl.java:1581)
原因是:MySQL中utf-8编码,一个字符占3个字节,但是微信Emoji表情字符,它的编码是utf8mb4编码的,一个字符占4个字节。就是因为这个原因,导致插入昵称时失败。
解决方案:
1、修改MySQL中对应表的昵称字段编码格式为utf8mb4;
2、放弃使用hibernate进行数据的存储或更新,改用纯jdbc的方式(hibernate的没研究过,不知道可不可以),代码片段如下:
String username = "root";
String password = "111111";
String className = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://127.0.0.1:3306/vote?autoReconnect=true&useUnicode=true&characterEncoding=utf-&zeroDateTimeBehavior=convertToNull";
Class.forName(className );
Connection conn = DriverManager.getConnection(url , username , password );
public static Long save(String sql, Object[] params){
Long ret = null;
ResultSet rs = null;
Connection conn = null;
PreparedStatement cmd = null;
try {
conn = getDBConnection();
conn.setAutoCommit(true);
//通过查询运行设置字符集的命令(这一句是重点)
conn.prepareStatement("set names utf8mb4").executeQuery();
cmd = conn.prepareStatement(sql);
if(params == null || params.length == 0){
return -1L;
}
for (int i = 0; i < params.length; i++) {
cmd.setObject(i+1, params[i]);
}
cmd.executeUpdate();
// 获取最后一条插入数据的自增列值
String sql2 = "select @@IDENTITY";
cmd = conn.prepareStatement(sql2);
rs = cmd.executeQuery();
if (rs.next()) {
ret = Long.parseLong(rs.getObject(1)+"");
}
} catch (SQLException e) {
e.printStackTrace();
logger.error(e.getMessage(), e);
} finally {
try {
if(cmd != null){
cmd.close();
}
if(rs != null){
rs.close();
}
if(conn != null){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return ret;
}
完成上述修改之后,emoji表情字符就可以正常的插入到MySQL中了。