UTF8和UTF8MB4
在早期MySQL版本中,使用只支持最長三字節的UTF8字符集便可以存放所有Unicode字符。隨着Unicode的完善,Unicode字符集收錄的字符數量越來越多,最新版本的UTF8需要使用1到4個字節來存放Unicode字符,而MySQL為保持版本兼容,依舊使用最多3字節的UTF8字符集,並在MySQL 5.5.3版本引入UTF8MB4字符集來支持4字節的Unicode字符。
漢字 '𤋮' 和 ' 𤋮 ' 是異體字,讀音均為xi,但兩個字的unicode不同:
𤋮 對應的UNICODE是 \ud850\udeee; 𤋮 對應的UTF8是 ��
𤋮 對應的HEX編碼是 %f0%a4%8b%ae
熙 對應的UNICODE是 \u7199
熙 對應的UTF8是 熙
熙 對應的HEX編碼是 %e7%86%99
在UTF8字符集模式下測試
創建測試表:
CREATE TABLE `tb5001` ( `ID` INT(11) NOT NULL AUTO_INCREMENT, `C1` VARBINARY(100) DEFAULT NULL, `C2` VARCHAR(100) DEFAULT NULL, PRIMARY KEY (`ID`) ) ENGINE=INNODB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8mb4
在UTF8字符集下測試
SET NAMES utf8; INSERT INTO TB5001(C1,C2) SELECT '𤋮','𤋮';
INSERT INTO TB5001(C1,C2) SELECT '熙','熙'; SELECT * FROM TB5001;
執行第一條INSERT有警告,警告信息為:
Warning Code : 1300 Invalid utf8 character string: 'F0A48B' Warning Code : 1366 Incorrect string value: '\xF0\xA4\x8B\xAE' for column 'C2' at row 1
查詢結果為:
在UTF8字符集下,VARCHAR類型"無法支持“四字節的"𤋮",但VARBINARY不受字符集影響。
在UTF8MB4字符集模式下測試
測試腳本
SET NAMES utf8mb4; INSERT INTO TB5001(C1,C2) SELECT '𤋮','𤋮'; INSERT INTO TB5001(C1,C2) SELECT '熙','熙'; SELECT * FROM TB5001;
測試中無任何警告,查詢結果:
在UTF8MB4字符集下,VARCHAR類型"完美支持“四字節的"𤋮",但VARBINARY不受字符集影響。
亂碼問題
表TB5001字符集已定義為UTF8MB4,表上C1列的字符集也是UTF8MB4,為啥還出現亂碼呢?
測試腳本:
SET NAMES utf8; SELECT * FROM TB5001; SET NAMES utf8mb4; SELECT * FROM TB5001;
測試對比圖:
雖然表上C1列的字符集是UTF8MB4,能存放4字節的字符,但:
1、對於ID=33的記錄,由於在插入時使用UTF8字符集,在插入到C1列前'𤋮'字已經發生亂碼,存儲到C1列中數據也是亂碼,因此無論讀取時使用UTF8還是UTF8MB4都是亂碼。
2、對於ID-35的記錄,由於在插入時使用UTF8MB4字符集,插入C1列前和存儲到C1中都正常,在讀取時使用UTF8MB4能正常讀取,但在讀取使用UTF8是亂碼。
SET NAMES x相當於執行下面三條語句:
SET character_set_client = x; SET character_set_results = x; SET character_set_connection = x;
要保證數據庫正常存儲4字節的表情符合生僻字,除將數據庫相關表和列設置為UTF8MB4外,還需要確保操作數據庫時使用UTF8MB4,需重點關注以下幾個方面:
1、數據庫啟動配置參數
2、應用與數據庫連接配置
3、DBA日常運維操作
如DBA操作過程中,使用mysql客戶端連接到數據庫執行操作,而mysql客戶端可能使用默認UTF8字符集(default-character-set),導出亂碼問題。
在xshell工具下粘貼下面代碼:
SELECT '𤋮','𤋮'; SELECT '熙','熙';
將代碼粘貼到vim工具中自動變為:
SELECT '<d850><deee>','<d850><deee>'; SELECT '熙','熙';
將代碼粘貼到mysql命令總變為:
因此建議DBA在日常運維中關注生僻字和表情符,避免異常。
參考:http://seanlook.com/2016/10/23/mysql-utf8mb4/