Application沒法傳遞Emoji字符到MySQL的問題

MySQL中沒法存儲Emoji字符,源自於MySQL 5.5以前utf8編碼只支持最大3個字節,而Emoji須要4個字節。從MySQL 5.5開始,其utf8編碼開始有了支持4個字節的utf8類型:utf8mb4 . java

一般,若是你的MySQL版本是5.5+但又沒法在某個具體的列存儲Emoji字符,就是源自於這個列的類型還停留於過去的utf8類型,沒有升級到最新的支持4字節的utf8mb4. mysql

解決方案的思路也很簡單,就是在確保你的MySQL是5.5+的前提下,將須要存儲Emoji字符的列的編碼改成utf8mb4. sql

網上的大部分資料採用了更改 "列、表、庫" 的編碼類型,再配上修改MySQL配置文件,並重啓MySQL的方式來解決問題:ui

-- 修改一列:
ALTER TABLE table_name CHANGE column_name column_name VARCHAR(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- 修改表:
ALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- 修改庫:
ALTER DATABASE database_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;

-- ==============================

-- 修改配置文件 /etc/my.cnf
[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

這樣的解決方案有些粗糙,並涉及到MySQL的重啓,對生產環境來說,重啓db是一件代價極其高昂的事情。編碼

事實上,若是隻是某個列存在Emoji字符的存儲問題,那就只須要修改這個列的編碼類型便可。若是確實須要修改到"表、庫"這個級別,那再作修改不遲。url

作完這一步後,應該能夠在db客戶端直接存儲Emoji字符了。可是,對於須要鏈接到MySQL的應用來說,僅僅上述步驟的修改還不夠,還沒法使應用將Emoji字符成功地存儲MySQL。這涉及到應用與MySQL創建鏈接的問題。code

因爲咱們想要不重啓MySQL,那麼MySQL當中默認給出的 "創建新鏈接" (set connection) 所支持的字符編碼依舊是utf8。雖然db裏面的某個特定的列已經支持了utf8mb4,但"鏈接"不支持對utf8mb4字符的傳輸,Emoji字符也就沒法順利運輸到db中。server

因此問題就變成了,如何在不重啓MySQL的前提下,從新設置connection的字符編碼。xml

有一條MySQL命令是 set names 'xxx' ,會將character_set_client、character_set_connection、character_set_results的編碼統一設置。使用這條命令 set names utf8mb4; 即可以達到咱們的目的。ci

但問題是,應該在哪裏設置這條命令呢?不少人會直接在本身的MySQL客戶端運行這條命令,但發現本身的應用依舊沒法正確傳遞Emoji字符。這是由於,當你在MySQL客戶端運行這條命令時,只是設置了你的客戶端同MySQL的connection字符編碼,但你的應用卻使用了本身的connection,固然沒法達到目的。

因此正確的作法是,你須要在本身應用創建connection後,在代碼中運行這條命令。

而若是你使用的是Druid DataSource(若是你使用的是Tomcat DataSource,那麼你能夠大膽切換到Druid DataSource),那麼這件事情就更容易了,只須要在配置文件的 connectionInitSqls 中完成這件事。以Java爲例,你只須要:

DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl(url);
dataSource.setUsername(userName);
dataSource.setPassword(password);

// set 'utf8mb4' to support emoji character
dataSource.setConnectionInitSqls(Arrays.asList("set names utf8mb4;"));

若是你使用的是xml來配置bean,則只須要:

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
  <property name="driverClassName" value="${jdbc-driver}"/>
  <property name="url" value="${jdbc-url}"/>
  <property name="username" value="${jdbc-user}"/>
  <property name="password" value="${jdbc-password}"/>
  
  <property name="connectionInitSqls" value="set names utf8mb4;"/>
  
</bean>

如此,便能在不重啓MySQL的狀況下讓你應用將Emoji字符傳遞到db中去。

相關文章
相關標籤/搜索