上周在做微信摄影投票时,遇到这么一个情况,在微信中,如果将用户昵称修改为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中了。