MySQL怎麼存文字不亂碼
MySQL裡怎麼儲存那些看起來會亂碼的字元?我在“UTF8字符集的表怎麼直接轉UTF8MB4”一文中介紹瞭如何把表字符集由UTF8直接轉換成UTF8MB4的幾種方法。
導讀
MySQL裡怎麼儲存那些看起來會亂碼的字元?
我在“UTF8字符集的表怎麼直接轉UTF8MB4”一文中介紹瞭如何把表字符集由UTF8直接轉換成UTF8MB4的幾種方法。
1、只修改字符集(使用預設校驗集)
- [email protected]> alter table t1 convert to character
2、同時修改表字符集和校驗集
- [email protected]> alter table t1 convert to character set utf8mb4 collate utf8mb4_bin;
3、只修改某列的字符集
- [email protected]> alter table t1 modify
4、同時修改某列的字符集和校驗集
- [email protected]> alter table t1 modify c1 varchar(20) character set utf8mb4 collate utf8mb4_unicode_ci not
好了,有個字符集為UTF8MB4的表中想儲存各類不同字符集的文字,有哪些注意事項億避免亂碼?
如果是通過WEB介面儲存資料,則建議在browser端、server端全都採用UTF8字符集,MySQL Server端採用UTF8/UTF8MB4均可(針對大多數文字,其實UTF8字符集就足夠儲存的了)。
其中,MySQL端的字符集設定比較讓人頭大,涉及到的字符集有好幾個:
- character_set_server,server端預設字符集;
- character_set_database,database預設字符集,若未設定,則和 character_set_server 的設定一樣;database中的 資料表/stored procedure/stored function 也可以自行設定字符集,若未指定,則和 character_set_database 的設定一樣;資料表中的字元型別列,也可以單獨設定字符集,若未設定,則和該表指定的字符集一樣;
- character_set_client,客戶端顯示讀取結果的字符集;
- character_set_connection,客戶端從server端讀取資料時傳輸字符集;
- character_set_results,server端將資料傳送給客戶端時的字符集;
可見,涉及到字符集的因素實在太多,因此我們強烈建議各個環節全部採用同一種字符集,避免出現意外狀況。
MySQL採用UTF8MB4字符集時,儲存文字實際消耗位元組數是由文字內容的位元組數決定的,並非總是需要4位元組,列舉幾種情況:
- 輸入字符集任意,且儲存ASCII字元時,每個字元需要1byte;
- 輸入字符集是GB2312,且儲存的字元是漢字時,每個字元需要2bytes;
- 輸入字符集是UTF8/UTF8MB4,且儲存的字元是低編碼漢字時,每個字元需要3bytes;
- 輸入字符集是UTF8/UTF8MB4,且儲存的字元是高編碼漢字時,每個字元需要4bytes;
- 輸入字符集是binary,且儲存的字元是高編碼漢字時,每個字元需要4bytes;
總結建議
- 從前端到後端(瀏覽器=>WEB Server=>MySQL連線層=>Server層=>DB層>TABLE層),儘可能使用同一種字符集;
- 儘可能採用大字符集,也就是優先順序:UTF8Mb4 > UTF8 > GBK > LATIN1;
- 採用邏輯備份資料時,切記要不定期進行恢復測試,我以前在這方面栽過一次,教訓慘痛。
附1,關於編碼簡介
- ASCII碼,佔7bit,由128個字元組成,包括大小寫字母、數字0-9、標點符號、非列印字元(換行符、製表符等4個)以及控制字元(退格、響鈴等)組成;
- latin1,佔1byte,在ASCII基礎上,增加128 ~ 255區間的字元;
- GB2312等CJK字符集,可變長字符集,最多佔2bytes,用於儲存常見的CJK字元;
- UTF8,可變長字符集,最多佔3bytes,可以囊括ASCII、CJK及其他絕大多數常用語言文字;這中間其實還有個UNICODE字符集,它也是2bytes的,也能囊括ASCII字元,但即便是ASCII字元也需要消耗2bytes,存在一定浪費,而用UTF8儲存ASCII字元時,實際只需要1byte,更為節省儲存空間;
- UTF8MB4,可變長字符集,最多佔4bytes,可以包含上面其他幾種字符集;同樣地,以UTF8MB4儲存ASCII字元時,實際上也是隻佔用1bytes,儲存一般的漢字佔用3bytes,而儲存個別漢字則需要4bytes,儲存emoji也至少需要4bytes;
附2,字符集相容線上測試
為了方便大家,我寫了個簡單的PHP介面供測試,可以提交一些不常見的漢字,或者emoji表情符,看看是否都能正常顯示。
開發這個介面時,發現釘釘中的個別表情符是由2個4位元組編碼組成的,也就是說一個emoji表情符,其實是需要8個位元組的。
這個介面最後輸出的格式是:
字串 : 位元組數
比如 "a齒a : 5" ,表示 "a齒a" 這個字串共消耗 5個位元組,因為 "齒" 其實只需要3個位元組來儲存,雖然看起來挺大一坨的。
相應的程式碼如下:
- select vchar, length(vchar) as vcharlen
測試介面連結: utf8mb4字符集相容性測試介面
如果想要寫入4位元組的漢字,可以從龍泉寺提供的字型檔拷貝過來,或者插入emoji表情符。