為什么不建議在 MySQL 中使用 UTF-8?

問題:“為什么不建議在 MySQL 中使用 UTF-8?”
記得去年我在往MySQL存入emoji表情????時,一直出錯,無法導入。后來找到辦法 -- 通過把 utf8 改成 utf8mb4 就可以了,并沒有深究。
一年后,我看到一篇文章講到emoji文字占4個字節(jié),通常要用utf-8去接收才行,其他編碼可能會出錯。我突然想到去年操作MySQL把utf8改成utf8mb4的事兒。
嗯?他本身不就是utf8編碼么!那我當時還改個錘子?
難道,MySQL的utf8不是真正的UTF-8編碼嗎??! 臥槽這。。MySQL有bug!
帶著疑問查詢了很多相關(guān)材料,才發(fā)現(xiàn)這竟然是MySQL的一個歷史遺留問題~~
我笑了,沒想到這么牛B的MySQL也會有這段往事。
1
將emoji文字直接寫入SQL中,執(zhí)行 insert 語句報錯;
INSERT INTO `csjdemo`.`student` (`ID`, `NAME`, `SEX`, `AGE`, `CLASS`, `GRADE`, `HOBBY`)
VALUES ('20', '陳哈哈??', '男', '20', '181班', '9年級', '看片兒');[Err] 1366 - Incorrect string value: '\xF0\x9F\x98\x93' for column 'NAME' at row 1
改了數(shù)據(jù)庫編碼、系統(tǒng)編碼以及表字段的編碼格式 → utf8mb4 之后,就可以了:
INSERT INTO `student` (`ID`, `NAME`, `SEX`, `AGE`, `CLASS`, `GRADE`, `HOBBY`)
VALUES (null, '陳哈哈????', '男', '20', '181班', '9年級', '看片兒');

2
MySQL 的“utf8”實際上不是真正的 UTF-8。
在MySQL中,“utf8”編碼只支持每個字符最多三個字節(jié),而真正的 UTF-8 是每個字符最多四個字節(jié)。
在utf8編碼中,中文是占3個字節(jié),其他數(shù)字、英文、符號占一個字節(jié)。
但emoji符號占4個字節(jié),一些較復雜的文字、繁體字也是4個字節(jié)。所以導致寫入失敗,應該改成utf8mb4。

如上圖中所示,這是編碼改成utf8mb4后入庫的數(shù)據(jù),大家可以清晰的對比一下所占的字符數(shù)、字節(jié)數(shù)。正因如此,4字節(jié)的內(nèi)容往utf8編碼中插入,肯定是不行的,插不進去啊,是吧(大潘攤手)。

MySQL 一直沒有修復這個 bug,他們在 2010 年發(fā)布了一個叫作“utf8mb4”的字符集,巧妙的繞過了這個問題。
當然,他們并沒有對新的字符集廣而告之(可能是因為這個 bug 讓他們覺得很尷尬),以致于現(xiàn)在網(wǎng)絡上仍然在建議開發(fā)者使用“utf8”,但這些建議都是錯誤的。
1. utf8mb4 才是真正的UTF-8
計算機讀取“01000011”,得到數(shù)字 67,因為 67 被編碼成“01000011”。
計算機在 Unicode 字符集中查找 67,找到了“C”。
我的電腦將“C”映射成 Unicode 字符集中的 67。
我的電腦將 67 編碼成“01000011”,并發(fā)送給 Web 服務器。
2. utf8 的簡史

使用 CHAR 定義列(在現(xiàn)在看來,CHAR 已經(jīng)是老古董了,但在那時,在 MySQL 中使用 CHAR 會更快,不過從 2005 年以后就不是這樣子了)。
將 CHAR 列的編碼設(shè)置為“utf8”。
3
