1. 程式人生 > >Emoji儲存到資料庫問題【小程式入坑系列】

Emoji儲存到資料庫問題【小程式入坑系列】

     目前使用的資料庫是mysql而且預設的資料字符集是“utf-8”,當小程式使用者的暱稱中含有emoji圖片的時候儲存到資料庫就會有問題。使用mysql資料庫的時候,如果字符集是UTF-8並且在java伺服器上,當儲存emoji表情的時候,會丟擲以上異常(比如微信開發獲取使用者暱稱,有的使用者的暱稱用的是emoji的影象)這是由於字符集不支援的異常,因為utf-8編碼有可能是兩個,三個,四個位元組,其中Emoji表情是四個位元組,而mysql的utf-8編碼最多三個位元組,所以導致資料插不進去。

典型的sql錯誤日誌如下

處理這種方式主要有2中方案,第一種方案是從資料庫入手,第二種方案從專案應用入手。

     由於大多數人都屬於開發者並非正在的後期維護,所有第一種方案雖然從本質上解決了問題,但是如果涉及到其他資料庫的影響,開發者一般也不會太在意而導致意外的事件發生,再其次,一個正在的大公司不會輕易因為你的一個專案而修改整個資料庫的字符集,同時你也沒有這個許可權私自修改。

     從專案應用入手對每個開發者來說都是最直接的表現方式,在程式碼裡改動既直觀又可以後期維護。

     先介紹第一種方案:從資料庫層面進行解決(mysql支援utf8mb4的版本是5.5.3+,必須升級到較新版本)

1.修改database,table,column字符集

ALTER DATABASE database_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
ALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE table_name CHANGE column_name VARCHAR(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
    
     2.修改mysql配置檔案my.cnf(window為my.ini)
[client]
default-character-set = utf8mb4
[mysql]
default-character-set = utf8mb4
[mysqld]
character-set-client-handshake = FALSE
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
init_connect='SET NAMES utf8mb4'

     3.用的是java伺服器,升級或者確保mysql connection版本高於5.1.13否則仍然不能試用utf8mb4)
     4.伺服器端的db配置檔案
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/database?useUnicode=true&characterEncoding=utf8&autoReconnect=true&rewriteBatchedStatements=TRUE
jdbc.username=root
jdbc.password=password

    如果升級了mysql-connector,其中的characterEncoding=utf8可以自動被識別為utf8mb4(相容原來的utf8),而
autoReconnection(當資料庫連線異常中斷時,是否自動重新連線?預設為false)強烈建議配上,忽略這個屬性,可能導致快取緣故 ,沒有讀取到DB最新的配置,導致一直無法試用utf8mb4字符集;
詳細可見 :http://segmentfault.com/a/1190000000616820

二.從應用層的方面進行解決
在獲得資料之後往資料庫存之前先進行編碼: 

        URLEncoder.encode(nickName, "utf-8");

當從資料庫中取出準備顯示的時候進行解碼, 

       URLDecoder.decode(nickname, "utf-8");

       從應用層進行解決的時候建議不要在物件getter,setter方法中直接編碼,因為放入物件的時候setter方法將nickname進行編碼,當插入資料庫的時候相當於從物件中呼叫getter方法將你參考取出這就將之前setter編碼過的nickname又重新解碼了,等於未對Nickname進行任何操作。依然會出現以上問題。

        最終展示效果如下:

       


           而資料實體類可以參照如下,不要在getNickName方法中呼叫編碼解碼,因為這樣做是完全沒有效果的,當插入資料庫的時候相當於從物件中呼叫getter方法將你參考取出這就將之前setter編碼過的nickname又重新解碼了,等於未對Nickname進行任何操作

 


     本文參考:http://www.cnblogs.com/dashuai01/p/4601204.html