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

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

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

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

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

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