MySQL怎么存文本不亂碼?
導讀
MySQL里怎么存儲那些看起來會亂碼的字符?
我在“UTF8字符集的表怎么直接轉(zhuǎn)UTF8MB4”一文中介紹了如何把表字符集由UTF8直接轉(zhuǎn)換成UTF8MB4的幾種方法。
1、只修改字符集(使用默認校驗集)
- yejr@imysql.com> alter table t1 convert to character set utf8mb4
2、同時修改表字符集和校驗集
- yejr@imysql.com> alter table t1 convert to character set utf8mb4 collate utf8mb4_bin;
3、只修改某列的字符集
- yejr@imysql.com> alter table t1 modify c1 varchar(20) character set utf8mb4 not null default ‘’
4、同時修改某列的字符集和校驗集
- yejr@imysql.com> alter table t1 modify c1 varchar(20) character set utf8mb4 collate utf8mb4_unicode_ci not null default ‘’
好了,有個字符集為UTF8MB4的表中想存儲各類不同字符集的文本,有哪些注意事項億避免亂碼?
如果是通過WEB接口存儲數(shù)據(jù),則建議在browser端、server端全都采用UTF8字符集,MySQL Server端采用UTF8/UTF8MB4均可(針對大多數(shù)文本,其實UTF8字符集就足夠存儲的了)。
其中,MySQL端的字符集設置比較讓人頭大,涉及到的字符集有好幾個:
- character_set_server,server端默認字符集;
- character_set_database,database默認字符集,若未設定,則和 character_set_server 的設定一樣;database中的 數(shù)據(jù)表/stored procedure/stored function 也可以自行設定字符集,若未指定,則和 character_set_database 的設置一樣;數(shù)據(jù)表中的字符類型列,也可以單獨設定字符集,若未設定,則和該表指定的字符集一樣;
- character_set_client,客戶端顯示讀取結(jié)果的字符集;
- character_set_connection,客戶端從server端讀取數(shù)據(jù)時傳輸字符集;
- character_set_results,server端將數(shù)據(jù)發(fā)送給客戶端時的字符集;
可見,涉及到字符集的因素實在太多,因此我們強烈建議各個環(huán)節(jié)全部采用同一種字符集,避免出現(xiàn)意外狀況。
MySQL采用UTF8MB4字符集時,存儲文本實際消耗字節(jié)數(shù)是由文本內(nèi)容的字節(jié)數(shù)決定的,并非總是需要4字節(jié),列舉幾種情況:
- 輸入字符集任意,且存儲ASCII字符時,每個字符需要1byte;
- 輸入字符集是GB2312,且存儲的字符是漢字時,每個字符需要2bytes;
- 輸入字符集是UTF8/UTF8MB4,且存儲的字符是低編碼漢字時,每個字符需要3bytes;
- 輸入字符集是UTF8/UTF8MB4,且存儲的字符是高編碼漢字時,每個字符需要4bytes;
- 輸入字符集是binary,且存儲的字符是高編碼漢字時,每個字符需要4bytes;
總結(jié)建議
- 從前端到后端(瀏覽器=>WEB Server=>MySQL連接層=>Server層=>DB層>TABLE層),盡可能使用同一種字符集;
- 盡可能采用大字符集,也就是優(yōu)先級:UTF8Mb4 > UTF8 > GBK > LATIN1;
- 采用邏輯備份數(shù)據(jù)時,切記要不定期進行恢復測試,我以前在這方面栽過一次,教訓慘痛。
附1,關(guān)于編碼簡介
- ASCII碼,占7bit,由128個字符組成,包括大小寫字母、數(shù)字0-9、標點符號、非打印字符(換行符、制表符等4個)以及控制字符(退格、響鈴等)組成;
- latin1,占1byte,在ASCII基礎上,增加128 ~ 255區(qū)間的字符;
- GB2312等CJK字符集,可變長字符集,最多占2bytes,用于存儲常見的CJK字符;
- UTF8,可變長字符集,最多占3bytes,可以囊括ASCII、CJK及其他絕大多數(shù)常用語言文字;這中間其實還有個UNICODE字符集,它也是2bytes的,也能囊括ASCII字符,但即便是ASCII字符也需要消耗2bytes,存在一定浪費,而用UTF8存儲ASCII字符時,實際只需要1byte,更為節(jié)省存儲空間;
- UTF8MB4,可變長字符集,最多占4bytes,可以包含上面其他幾種字符集;同樣地,以UTF8MB4存儲ASCII字符時,實際上也是只占用1bytes,存儲一般的漢字占用3bytes,而存儲個別漢字則需要4bytes,存儲emoji也至少需要4bytes;
附2,字符集兼容在線測試
為了方便大家,我寫了個簡單的PHP接口供測試,可以提交一些不常見的漢字,或者emoji表情符,看看是否都能正常顯示。
開發(fā)這個接口時,發(fā)現(xiàn)釘釘中的個別表情符是由2個4字節(jié)編碼組成的,也就是說一個emoji表情符,其實是需要8個字節(jié)的。
這個接口***輸出的格式是:
字符串 : 字節(jié)數(shù)
比如 "a齒a : 5" ,表示 "a齒a" 這個字符串共消耗 5個字節(jié),因為 "齒" 其實只需要3個字節(jié)來存儲,雖然看起來挺大一坨的。
相應的代碼如下:
- select vchar, length(vchar) as vcharlen
測試接口鏈接: utf8mb4字符集兼容性測試接口
如果想要寫入4字節(jié)的漢字,可以從龍泉寺提供的字庫拷貝過來,或者插入emoji表情符。
參考及延伸閱讀
- UTF8字符集的表怎么直接轉(zhuǎn)UTF8MB4
- FAQ系列 - 調(diào)用存儲過程時報錯 Illegal mix of collations
- 聽說JOIN的列類型一定要一樣
- https://dev.mysql.com/doc/refman/5.7/en/charset-unicode-conversion.html
- https://dev.mysql.com/doc/refman/5.7/en/cast-functions.html
- http://imysql.com/charset_tips
- http://imysql.com/utf8mb4/utf8mb4.php
- http://www.cnblogs.com/chenwenbiao/archive/2011/08/11/2134503.html
- http://www.imkevinyang.com/2010/06/關(guān)于字符編碼,你所需要知道的.html