MySQL設定utf8mb4編碼

dbasdk發表於2014-09-15
有一個專案需要儲存ios的表情(emoji表情)
這種表情雖然是utf8編碼,但是一個字元需要佔用4個位元組,而MySQL utf8編碼只能存放3位元組的字元。
在MySQL 5.6中,可以設定編碼為utf8mb4,這個字符集是utf8的超集。

實驗環境
MySQL   5.6.14
JDBC    5.1.31
測試表  create table test( content varchar(50) )engine=innodb,charset=utf8mb4;
測試程式:
  1. import java.io.IOException;
  2. import java.net.URLDecoder;
  3. import java.net.URLEncoder;
  4. import java.sql.Connection;
  5. import java.sql.DriverManager;
  6. import java.sql.PreparedStatement;

  7. import javax.servlet.ServletException;
  8. import javax.servlet.annotation.WebServlet;
  9. import javax.servlet.http.HttpServlet;
  10. import javax.servlet.http.HttpServletRequest;
  11. import javax.servlet.http.HttpServletResponse;

  12. /**
  13.  * Servlet implementation class CharsetTest
  14.  */
  15. @WebServlet("/CharsetTest")
  16. public class CharsetTest extends HttpServlet {
  17.     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  18.         String str = request.getParameter("content");
  19.         str = URLDecoder.decode(str, "utf8");
  20.         System.out.println(URLEncoder.encode(str, "utf8"));

  21.         try {
  22.             save(str);
  23.         } catch (Exception e) {
  24.             e.printStackTrace();
  25.         }

  26.     }

  27.     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  28.         doGet(request, response);
  29.     }

  30.     private static void save(String content) throws Exception {
  31.         /**
  32.          * create table test( content varchar(50) )engine=innodb,charset=utf8mb4
  33.          */
  34.         Class.forName("com.mysql.jdbc.Driver");
  35.         Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/xx", "xx", "xx");

  36.         connection.setAutoCommit(true);
  37.         
  38.         //通過查詢執行設定字符集的命令
  39.         //connection.prepareStatement("set names utf8mb4").executeQuery();
  40.         
  41.         PreparedStatement cmd = connection.prepareStatement("insert into test values(?)");
  42.         cmd.setString(1, content);
  43.         cmd.executeUpdate();

  44.         cmd.close();
  45.         connection.close();
  46.     }
  47. }
測試連結:
兩次編碼後的ios表情:
http://127.0.0.1:8080/Web/CharsetTest?content=%25F0%259F%2598%2584

兩次編碼後的中文:
http://127.0.0.1:8080/Web/CharsetTest?content=%25E4%25B8%25AD%25E6%2596%2587

關於兩次編碼參見:
http://blog.itpub.net/29254281/viewspace-775925/


首先,修改mysql的配置檔案
character_set_server=utf8mb4
然後重啟資料庫和中介軟體.
點選兩個測試的連結,檢視資料庫,發現資料成功插入。


這個過程理論上是不需要重啟資料庫的。
但是實際測試中發現,如果不重啟資料庫,則插入會報錯。


如果運氣好,直接修改character_set_server引數,重啟資料庫,一切正常,就OK了。
運氣不好(比如我),就很悲劇了。
我在生產庫上修改了配置,並且重啟了資料庫。
居然發現ios的表情插入資料庫都是亂碼(全是問號 ????)
更悲劇的是,過了幾分鐘突然發現線上新插入的資料都是亂碼(也都是問號)。
幸虧發現的早,還原了資料庫的配置,否則執行幾天之後發現,估計就得收拾小包袱走人了。

後來排查到這個問題是JDBC驅動造成的,線上JDBC驅動的版本是mysql-connector-java-5.1.6-bin
如果MySQL伺服器設定為utf8mb4 高版本的JDBC驅動沒有關係,但是低版本的驅動插入之後,就是下面這個樣子。
所有輸入的非英文字元都是亂碼了。


因為JDBC驅動並不支援utf8mb4字符集,所以不能設定JDBC URL的characterEncoding



不過還有三種方式可以設定字符集
1.不顯式設定字符集,繼承伺服器的配置

2.在執行SQL之前,執行set names 的查詢  (Query方式)


3.設定MySQL init_connect引數


經過測試各種因素的結果如下所示:
 
JDBC版本
普通中文
蘋果表情
伺服器utf8編碼
5.1.6    
正常
插入報錯
 
5.1.6  Query
正常
正常
 
5.1.6  init_connect
正常
插入報錯
 
5.1.31
正常
插入報錯
 
5.1.31 Query
正常
正常
 
5.1.31 init_connect
正常
插入報錯
伺服器utf8mb4編碼
5.1.6
亂碼
亂碼
 
5.1.6  Query
亂碼
亂碼
 
5.1.6  init_connect
亂碼
亂碼
 
5.1.31
正常
正常
 
5.1.31 Query
正常
正常
 
5.1.31 init_connect
正常
正常
 
總結:
1.修改了character_set_server引數,需要重啟資料庫
2.使用高版本的JDBC



參考:
http://blog.csdn.net/ichocolatekapa/article/details/26671669
http://mckobe23.blog.51cto.com/826570/1067388
http://www.tuicool.com/articles/zAnEV3

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29254281/viewspace-1219800/,如需轉載,請註明出處,否則將追究法律責任。

相關文章