1. 程式人生 > >MySQL怎麼存文字不亂碼

MySQL怎麼存文字不亂碼

MySQL裡怎麼儲存那些看起來會亂碼的字元?我在“UTF8字符集的表怎麼直接轉UTF8MB4”一文中介紹瞭如何把表字符集由UTF8直接轉換成UTF8MB4的幾種方法。



MySQL怎麼存文字不亂碼?

導讀

MySQL裡怎麼儲存那些看起來會亂碼的字元?

我在“UTF8字符集的表怎麼直接轉UTF8MB4”一文中介紹瞭如何把表字符集由UTF8直接轉換成UTF8MB4的幾種方法。

1、只修改字符集(使用預設校驗集)


 
  1. [email protected]alter table t1 convert to character
     set utf8mb4 

2、同時修改表字符集和校驗集


 
  1. [email protected]alter table t1 convert to  character set utf8mb4 collate utf8mb4_bin; 

3、只修改某列的字符集


 
  1. [email protected]alter table t1 modify
     c1 varchar(20)  character set utf8mb4 not null default ‘’ 

4、同時修改某列的字符集和校驗集


 
  1. [email protected]alter table t1 modify c1 varchar(20)  character set utf8mb4  collate utf8mb4_unicode_ci  not
     null default ‘’ 

好了,有個字符集為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;

總結建議

  1. 從前端到後端(瀏覽器=>WEB Server=>MySQL連線層=>Server層=>DB層>TABLE層),儘可能使用同一種字符集;
  2. 儘可能採用大字符集,也就是優先順序:UTF8Mb4 > UTF8 > GBK > LATIN1;
  3. 採用邏輯備份資料時,切記要不定期進行恢復測試,我以前在這方面栽過一次,教訓慘痛。

附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個位元組來儲存,雖然看起來挺大一坨的。

相應的程式碼如下:


 
  1. select vchar, length(vchar) as vcharlen 

測試介面連結: utf8mb4字符集相容性測試介面

如果想要寫入4位元組的漢字,可以從龍泉寺提供的字型檔拷貝過來,或者插入emoji表情符。