異常信息
Cause: java.sql.SQLException:
Incorrect string value: '\xF0\x9F\x8D\x8B\xE5\xBB...' for column 'nick_name' at row 1
異常背景
抽獎大轉盤,抽獎后需要保存用戶抽獎記錄,用戶再次進入游戲時根據抽獎記錄判斷剩余抽獎機會。保存抽獎記錄時需要保存用戶open_id,昵稱,抽獎時間等信息,保存昵稱時異常,沒有成功記錄抽獎導致剩余機會不減,用戶可多次抽獎。
保存接口請求參數:
異常分析
昵稱包含特殊字符,數據庫定義的數據類型、字符集不支持,所以保存失敗了。
解決辦法
MySQL在5.5.3版本之后增加了這個utf8mb4的編碼,mb4就是most bytes 4的意思,專門用來兼容四字節的unicode。低版本的MySQL
支持的utf8編碼,最大字符長度為 3 字節,如果遇到 4 字節的字符就會出現錯誤了,其中Emoji表情是四個字節,導致插不進去。
解決這個辦法可以從數據庫層面上解決,即修改數據庫的字段定義,如下方案1;或者從應用層面解決,如下方案2。
方案1:修改數據庫字段字符集
mysql數據庫中,將nick_name字段字符集由utf8修改為utf8mb4,數據庫鏈接中將字符集由utf8改為utf8mb4。如下:
url: "jdbc:mysql://localhost:3306/big-turntable?useUnicode=true&characterEncoding=utf8mb4&useSSL=false"
查看日志和數據庫,插入不再異常。
方案2:使用 Base64 編碼與解碼昵稱
//Base64編碼保存昵稱
String nickname = record.getNickName();
if(stringutil.isNotEmpty(nickname)){nickname = Base64.getEncoder().encodeTostring(nickname.getBytes( charsetName: “utf-8”));record.setNickName(nickname);
} //Base64解碼昵稱
if(stringutil.isNotEmpty(record.getNickName())){String nickName =record.getNickName();String nickName = new String(Base64.getDecoder().decode(nickName), charsetName: "UTF-8");nickNameMap.put(record.getPriceId(),nickName);
}