异常:
Caused by: java.sql.SQLException: Incorrect string value: '\xF0\x9F\xA4\x97 \xF0...' for column 'name' at row 1
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:957) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3878) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3814) at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2478) at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2625) at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2551) at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1861) at com.mysql.jdbc.PreparedStatement.execute(PreparedStatement.java:1192) at org.apache.commons.dbcp.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:172) at org.apache.commons.dbcp.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:172) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.apache.ibatis.logging.jdbc.PreparedStatementLogger.invoke(PreparedStatementLogger.java:45) at com.sun.proxy.$Proxy21.execute(Unknown Source) at org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:23) at org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:51) at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:29) at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:74) at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:43) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:44) at com.sun.proxy.$Proxy20.update(Unknown Source) at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:118) ... 61 more异常原因:
数据库一般设置的编码格式是utf-8格式,而utf-8只包含3个字节编码,然而现在出现了4个字节编码格式,导致程序识别失败。
两种解决方法
1)把数据库编码格式设置成utf8mb4格式,其对应数据表也设置成其utf8mb4编码格式
2)直接过滤掉其多余的编码格式字节。使用其过滤工具类进行过滤,从而达到目的
public class UTF8Utils { public static MaphexMap = new HashMap (); public static Map byteMap = new HashMap (); static { hexMap.put("0", 2); hexMap.put("1", 2); hexMap.put("2", 2); hexMap.put("3", 2); hexMap.put("4", 2); hexMap.put("5", 2); hexMap.put("6", 2); hexMap.put("7", 2); hexMap.put("c", 4); hexMap.put("d", 4); hexMap.put("e", 6); hexMap.put("f", 8); byteMap.put("0", 1); byteMap.put("1", 1); byteMap.put("2", 1); byteMap.put("3", 1); byteMap.put("4", 1); byteMap.put("5", 1); byteMap.put("6", 1); byteMap.put("7", 1); byteMap.put("c", 2); byteMap.put("d", 2); byteMap.put("e", 3); byteMap.put("f", 4); } /** * 是否包含4字节UTF-8编码的字符(先转换16进制再判断) * @param s 字符串 * @return 是否包含4字节UTF-8编码的字符 */ public static boolean contains4BytesChar(String s) { if (s == null || s.trim().length() == 0) { return false; } String hex = UTF8Utils.bytesToHex(s.getBytes());// System.out.println("full hex : " + hex); String firstChar = null; while (hex != null && hex.length() > 1) { firstChar = hex.substring(0, 1);// System.out.println("firstChar : " + firstChar); if ("f".equals(firstChar)) {// System.out.println("it is f start, it is 4 bytes, return."); return true; } if (hexMap.get(firstChar) == null) {// System.out.println("it is f start, it is 4 bytes, return."); // todo, throw exception for this case return false; } hex = hex.substring(hexMap.get(firstChar), hex.length());// System.out.println("remain hex : " + hex); } return false; } /** * 是否包含4字节UTF-8编码的字符 * @param s 字符串 * @return 是否包含4字节UTF-8编码的字符 */ public static boolean contains4BytesChar2(String s) { if (s == null || s.trim().length() == 0) { return false; } byte[] bytes = s.getBytes(); if (bytes == null || bytes.length == 0) { return false; } int index = 0; byte b; String hex = null; String firstChar = null; int step; while (index <= bytes.length - 1) {// System.out.println("while loop, index : " + index); b = bytes[index]; hex = byteToHex(b); if (hex == null || hex.length() < 2) {// System.out.println("fail to check whether contains 4 bytes char(1 byte hex char too short), default return false."); // todo, throw exception for this case return false; } firstChar = hex.substring(0, 1); if (firstChar.equals("f")) { return true; } if (byteMap.get(firstChar) == null) {// System.out.println("fail to check whether contains 4 bytes char(no firstchar mapping), default return false."); // todo, throw exception for this case return false; } step = byteMap.get(firstChar);// System.out.println("while loop, index : " + index + ", step : " + step); index = index + step; } return false; } /** * 去除4字节UTF-8编码的字符 * @param s 字符串 * @return 已去除4字节UTF-8编码的字符 */ public static byte[] remove4BytesUTF8Char(String s) { byte[] bytes = s.getBytes(); byte[] removedBytes = new byte[bytes.length]; int index = 0; String hex = null; String firstChar = null; for (int i = 0; i < bytes.length; ) { hex = UTF8Utils.byteToHex(bytes[i]); if (hex == null || hex.length() < 2) {// System.out.println("fail to check whether contains 4 bytes char(1 byte hex char too short), default return false."); // todo, throw exception for this case return null; } firstChar = hex.substring(0, 1); if (byteMap.get(firstChar) == null) {// System.out.println("fail to check whether contains 4 bytes char(no firstchar mapping), default return false."); // todo, throw exception for this case return null; } if (firstChar.equals("f")) { for (int j = 0; j < byteMap.get(firstChar); j++) { i++; } continue; } for (int j = 0; j < byteMap.get(firstChar); j++) { removedBytes[index++] = bytes[i++]; } } return Arrays.copyOfRange(removedBytes, 0, index); } /** * 将字符串的16进制转换为HEX,并按每个字符的16进制分隔格式化 * @param s 字符串 */ public static String splitForReading(String s) { if (s == null || s.trim().length() == 0) { return ""; } String hex = UTF8Utils.bytesToHex(s.getBytes());// System.out.println("full hex : " + hex); if (hex == null || hex.length() == 0) {// System.out.println("fail to translate the bytes to hex."); // todo, throw exception for this case return ""; } StringBuilder sb = new StringBuilder(); int index = 0; String firstChar = null; String splittedString = null; while (index < hex.length()) { firstChar = hex.substring(index, index + 1); if (hexMap.get(firstChar) == null) {// System.out.println("fail to check whether contains 4 bytes char(no firstchar mapping), default return false."); // todo, throw exception for this case return ""; } splittedString = hex.substring(index, index + hexMap.get(firstChar)); sb.append(splittedString).append(" "); index = index + hexMap.get(firstChar); }// System.out.println("formated sb : " + sb); return sb.toString(); } /** * 字节数组转十六进制 * @param bytes 字节数组 * @return 十六进制 */ public static String bytesToHex(byte[] bytes) { if (bytes == null || bytes.length == 0) { return null; } StringBuilder sb = new StringBuilder(); for (int i = 0; i < bytes.length; i++) { int r = bytes[i] & 0xFF; String hexResult = Integer.toHexString(r); if (hexResult.length() < 2) { sb.append(0); // 前补0 } sb.append(hexResult); } return sb.toString(); } /** * 字节转十六进制 * @param b 字节 * @return 十六进制 */ public static String byteToHex(byte b) { int r = b & 0xFF;//获得低8位 String hexResult = Integer.toHexString(r); StringBuilder sb = new StringBuilder(); if (hexResult.length() < 2) { sb.append(0); // 前补0 } sb.append(hexResult); return sb.toString(); }}