mysql中utf8和utf8mb4的详解用法与区别
一.簡介
MySQL在5.5.3之后增加了這個utf8mb4的編碼,mb4就是most bytes 4的意思,專門用來兼容四字節的unicode。好在utf8mb4是utf8的超集,除了將編碼改為utf8mb4外不需要做其他轉換。當然,為了節省空間,一般情況下使用utf8也就夠了。
二.內容描述
那上面說了既然utf8能夠存下大部分中文漢字,那為什么還要使用utf8mb4呢? 原來mysql支持的 utf8 編碼最大字符長度為 3 字節,如果遇到 4 字節的寬字符就會插入異常了。三個字節的 UTF-8 最大能編碼的 Unicode 字符是 0xffff,也就是 Unicode 中的基本多文種平面(BMP)。也就是說,任何不在基本多文本平面的 Unicode字符,都無法使用 Mysql 的 utf8 字符集存儲。包括 Emoji 表情(Emoji 是一種特殊的 Unicode 編碼,常見于 ios 和 android 手機上),和很多不常用的漢字,以及任何新增的 Unicode 字符等等。
三.問題根源
最初的 UTF-8 格式使用一至六個字節,最大能編碼 31 位字符。最新的 UTF-8 規范只使用一到四個字節,最大能編碼21位,正好能夠表示所有的 17個 Unicode 平面。
utf8 是 Mysql 中的一種字符集,只支持最長三個字節的 UTF-8字符,也就是 Unicode 中的基本多文本平面。
Mysql 中的 utf8 為什么只支持持最長三個字節的 UTF-8字符呢?可能是因為 Mysql 剛開始開發那會,Unicode 還沒有輔助平面這一說呢。那時候,Unicode 委員會還做著 “65535 個字符足夠全世界用了”的美夢。Mysql 中的字符串長度算的是字符數而非字節數,對于 CHAR 數據類型來說,需要為字符串保留足夠的長。當使用 utf8 字符集時,需要保留的長度就是 utf8 最長字符長度乘以字符串長度,所以這里理所當然的限制了 utf8 最大長度為 3,比如 CHAR(100) Mysql 會保留 300字節長度。至于后續的版本為什么不對 4 字節長度的 UTF-8 字符提供支持,我想一個是為了向后兼容性的考慮,還有就是基本多文種平面之外的字符確實很少用到。
要在 Mysql 中保存 4 字節長度的 UTF-8 字符,需要使用 utf8mb4 字符集,但只有 5.5.3 版本以后的才支持(查看版本: select version();)。我覺得,為了獲取更好的兼容性,應該總是使用 utf8mb4 而非 utf8. 對于 CHAR 類型數據,utf8mb4 會多消耗一些空間,根據 Mysql 官方建議,使用 VARCHAR 替代 CHAR。
四.utf8升級utf8mb4問題
utf8mb4 字符集(4字節 UTF-8 Unicode 編碼)
UTF-8字符集每個字符最多使用三個字節,并且只包含基本多語言面 (Basic Multilingual Plane,BMP)字符。
utf8mb4 字符集使用最多每字符四個字節支持補充字符:
對于 BMP字符 UTF8 和 utf8mb4 具有相同的存儲特性:相同的代碼值,相同的編碼,相同的長度。
對于補充字符,UTF8不能儲存所有的字符,而utf8mb4需要四個字節來存儲它。因為UTF8不能存儲所有的字符,你的 utf8 列中都沒有補充字符,因此從舊版本的MySQL UTF8 升級數據時 不用擔心字符轉換或丟失數據。
utf8mb4 是 utf8 的超集,所以像下面的連接字符串操作,其結果字符集是 utf8mb4 排序規則(一組規則,定義如何對字符串進行比較和排序)是 utf8mb4_col:
同樣,下面的 WHERE 子句中的內容比較根據 utf8mb4_col 規則:
SELECT * FROM utf8_tbl, utf8mb4_tbl WHERE utf8_tbl.utf8_col = utf8mb4_tbl.utf8mb4_col;如上面所說到的: 要使用 utf8mb4 節省空間,使用 VARCHAR 替換 CHAR。否則,MySQL必須為使用 utf8mb4字符集的列的每一個字符保留四字節的空間,因為其最大長度可能是四字節。例如,MySQL必須為一個使用 utf8mb4 字符集的 char(10)的列保留40字節空間。
五.utf8升級utf8mb4具體步驟
首先將我們數據庫默認字符集由utf8 更改為utf8mb4,對應的表默認字符集也更改為utf8mb4 已經存儲表情的字段默認字符集也做了相應的調整。
SQL 語句
修改MySQL配置文件
新增如下參數:
檢查環境變量 和測試 SQL 如下:
SHOW VARIABLES WHERE Variable_name LIKE 'character\_set\_%' OR Variable_name LIKE 'collation%';
注意:MySQL版本必須為5.5.3以上版本,否則不支持字符集utf8mb4
六.建議
建議普通表使用utf8, 如果這個表需要支持emoji就使用utf8mb4
新建mysql庫或者表的時候還有一個排序規則
utf8_unicode_ci比較準確,utf8_general_ci速度比較快。通常情況下 utf8_general_ci的準確性就夠我們用的了,在我看過很多程序源碼后,發現它們大多數也用的是utf8_general_ci,所以新建數據 庫時一般選用utf8_general_ci就可以了
如果是utf8mb4那么對應的就是 utf8mb4_general_ci utf8mb4_unicode_ci
七.utf8_unicode_ci與utf8_general_ci的區別
當前,utf8_unicode_ci校對規則僅部分支持Unicode校對規則算法。一些字符還是不能支持。并且,不能完全支持組合的記號。這主要影響越南和俄羅斯的一些少數民族語言,如:Udmurt 、Tatar、Bashkir和Mari。
utf8_unicode_ci的最主要的特色是支持擴展,即當把一個字母看作與其它字母組合相等時。例如,在德語和一些其它語言中‘?’等于‘ss’。
utf8_general_ci是一個遺留的 校對規則,不支持擴展。它僅能夠在字符之間進行逐個比較。這意味著utf8_general_ci校對規則進行的比較速度很快,但是與使用utf8_unicode_ci的校對規則相比,比較正確性較差)。
例如,使用utf8_general_ci和utf8_unicode_ci兩種 校對規則下面的比較相等:
? = A
? = O
ü = U
兩種校對規則之間的區別是,對于utf8_general_ci下面的等式成立:? = s
但是,對于utf8_unicode_ci下面等式成立:? = ss
對于一種語言僅當使用utf8_unicode_ci排序做的不好時,才執行與具體語言相關的utf8字符集 校對規則。例如,對于德語和法語,utf8_unicode_ci工作的很好,因此不再需要為這兩種語言創建特殊的utf8校對規則。
utf8_general_ci也適用與德語和法語,除了‘?’等于‘s’,而不是‘ss’之外。如果你的應用能夠接受這些,那么應該使用utf8_general_ci,因為它速度快。否則,使用utf8_unicode_ci,因為它比較準確。
八.案例
查詢:CREATE TABLE test_session ( sessionId varchar(255) NOT NULL, userId int(10) unsigned DEFAULT NULL, createAt datetime DEFAULT NULL,...錯誤代碼: 1071 Specified key was too long; max key length is 767 bytes如上,報錯,當使用utf8mb4編碼后,主鍵id的長度設置255,太長,只能設置小于191的
其中:
max key length is 767 bytes utf8: 767/3=255.6666666666667 utf8mb4: 767/4=191.75九.深入Mysql字符集設置
基本概念
? 字符(Character)是指人類語言中最小的表義符號。例如’A’、’B’等;
? 給定一系列字符,對每個字符賦予一個數值,用數值來代表對應的字符,這一數值就是字符的編碼(Encoding)。例如,我們給字符’A’賦予數值0,給字符’B’賦予數值1,則0就是字符’A’的編碼;
? 給定一系列字符并賦予對應的編碼后,所有這些字符和編碼對組成的集合就是字符集(Character Set)。例如,給定字符列表為{‘A’,'B’}時,{‘A’=>0, ‘B’=>1}就是一個字符集;
? 字符序(Collation)是指在同一字符集內字符之間的比較規則;
? 確定字符序后,才能在一個字符集上定義什么是等價的字符,以及字符之間的大小關系;
? 每個字符序唯一對應一種字符集,但一個字符集可以對應多種字符序,其中有一個是默認字符序(Default Collation);
? MySQL中的字符序名稱遵從命名慣例:以字符序對應的字符集名稱開頭;以_ci(表示大小寫不敏感)、_cs(表示大小寫敏感)或_bin(表示按編碼值比較)結尾。例如:在字符序“utf8_general_ci”下,字符“a”和“A”是等價的;
MySQL字符集設置
? 系統變量:
– character_set_server:默認的內部操作字符集
– character_set_client:客戶端來源數據使用的字符集
– character_set_connection:連接層字符集
– character_set_results:查詢結果字符集
– character_set_database:當前選中數據庫的默認字符集
– character_set_system:系統元數據(字段名等)字符集
– 還有以collation_開頭的同上面對應的變量,用來描述字符序。
? 用introducer指定文本字符串的字符集:
– 格式為:[_charset] ‘string’ [COLLATE collation]
– 例如:
? SELECT _latin1 ‘string’;
? SELECT _utf8 ‘你好’ COLLATE utf8_general_ci;
– 由introducer修飾的文本字符串在請求過程中不經過多余的轉碼,直接轉換為內部字符集處理。
MySQL中的字符集轉換過程
MySQL Server收到請求時將請求數據從character_set_client轉換為character_set_connection;
進行內部操作前將請求數據從character_set_connection轉換為內部操作字符集,其確定方法如下:
? 使用每個數據字段的CHARACTER SET設定值;
? 若上述值不存在,則使用對應數據表的DEFAULT CHARACTER SET設定值(MySQL擴展,非SQL標準);
? 若上述值不存在,則使用對應數據庫的DEFAULT CHARACTER SET設定值;
? 若上述值不存在,則使用character_set_server設定值。
常見問題解析
? 向默認字符集為utf8的數據表插入utf8編碼的數據前沒有設置連接字符集,查詢時設置連接字符集為utf8
– 插入時根據MySQL服務器的默認設置,character_set_client、character_set_connection和character_set_results均為latin1;
– 插入操作的數據將經過latin1=>latin1=>utf8的字符集轉換過程,這一過程中每個插入的漢字都會從原始的3個字節變成6個字節保存;
– 查詢時的結果將經過utf8=>utf8的字符集轉換過程,將保存的6個字節原封不動返回,產生亂碼……
? 向默認字符集為latin1的數據表插入utf8編碼的數據前設置了連接字符集為utf8
– 插入時根據連接字符集設置,character_set_client、character_set_connection和character_set_results均為utf8;
– 插入數據將經過utf8=>utf8=>latin1的字符集轉換,若原始數據中含有\u0000~\u00ff范圍以外的Unicode字 符,會因為無法在latin1字符集中表示而被轉換為“?”(0x3F)符號,以后查詢時不管連接字符集設置如何都無法恢復其內容了。
檢測字符集問題的一些手段
? SHOW CHARACTER SET;
? SHOW COLLATION;
? SHOW VARIABLES LIKE ‘character%’;
? SHOW VARIABLES LIKE ‘collation%’;
? SQL函數HEX、LENGTH、CHAR_LENGTH
? SQL函數CHARSET、COLLATION
使用MySQL字符集時的建議
? 建立數據庫/表和進行數據庫操作時盡量顯式指出使用的字符集,而不是依賴于MySQL的默認設置,否則MySQL升級時可能帶來很大困擾;
? 數據庫和連接字符集都使用latin1時雖然大部分情況下都可以解決亂碼問題,但缺點是無法以字符為單位來進行SQL操作,一般情況下將數據庫和連接字符集都置為utf8是較好的選擇;
? 使用mysql C API時,初始化數據庫句柄后馬上用mysql_options設定MYSQL_SET_CHARSET_NAME屬性為utf8,這樣就不用顯式地用 SET NAMES語句指定連接字符集,且用mysql_ping重連斷開的長連接時也會把連接字符集重置為utf8;
? 對于mysql PHP API,一般頁面級的PHP程序總運行時間較短,在連接到數據庫以后顯式用SET NAMES語句設置一次連接字符集即可;但當使用長連接時,請注意保持連接通暢并在斷開重連后用SET NAMES語句顯式重置連接字符集。
其他注意事項
? my.cnf中的default_character_set設置只影響mysql命令連接服務器時的連接字符集,不會對使用libmysqlclient庫的應用程序產生任何作用!
? 對字段進行的SQL函數操作通常都是以內部操作字符集進行的,不受連接字符集設置的影響。
? SQL語句中的裸字符串會受到連接字符集或introducer設置的影響,對于比較之類的操作可能產生完全不同的結果,需要小心!
參考鏈接:https://my.oschina.net/xsh1208/blog/1052781
總結
以上是生活随笔為你收集整理的mysql中utf8和utf8mb4的详解用法与区别的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 你了解什么是Web服务器吗?
- 下一篇: 考研完形填空 方法技巧*