溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何解決MySQL對(duì)JSON類型UTF-8編碼導(dǎo)致中文亂碼問題

發(fā)布時(shí)間:2021-10-25 09:47:59 來源:億速云 閱讀:991 作者:柒染 欄目:大數(shù)據(jù)

如何解決MySQL對(duì)JSON類型UTF-8編碼導(dǎo)致中文亂碼問題,針對(duì)這個(gè)問題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問題的小伙伴找到更簡(jiǎn)單易行的方法。

我們來學(xué)習(xí)字符編碼,在學(xué)習(xí)的過程中,我發(fā)現(xiàn)對(duì)于MySQL中JSON類型的編碼導(dǎo)致數(shù)據(jù)中文出現(xiàn)亂碼還有可深挖之處,接下來我們來分析一下,若有錯(cuò)誤之處,還請(qǐng)批評(píng)指出。

評(píng)論中指出任何不在基本多文本平面的Unicode字符,都無法使用MySQL的utf8字符集存儲(chǔ),包括 Emoji 表情(Emoji 是一種特殊的Unicode 編碼,常見于 IOS 和 Android 手機(jī)上)和很多不常用的漢字,以及任何新增的 Unicode 字符等等(utf8的缺點(diǎn))。

首先我們了解下什么是Unicode,Unicode是通用字符集,它是一種標(biāo)準(zhǔn),該標(biāo)準(zhǔn)在一處定義了編寫在計(jì)算機(jī)上使用的大多數(shù)活動(dòng)語言所需的所有字符,它的目標(biāo)是成為并且在很大程度上已經(jīng)是已編碼的所有其他字符集的超集。在計(jì)算機(jī)或網(wǎng)絡(luò)中的文本我們通過字符組成,字符代表字母、標(biāo)點(diǎn)符號(hào)或其他符號(hào)。不同的組織收集了不同的字符集并為其創(chuàng)建了編碼-一個(gè)字符集可能僅覆蓋基于拉丁語的西歐語言(不包括保加利亞或希臘等歐盟國家),另一個(gè)可能覆蓋特定的遠(yuǎn)東語言(例如(例如日語),其他語言可能是以特殊方式設(shè)計(jì)的,代表世界上某處其他語言的眾多語言之一。但是我們并不能保證應(yīng)用程序?qū)⒅С炙芯幋a,也不能保證給定的編碼將滿足我們代表給定語言的所有需求,另外,通常不可能在同一網(wǎng)頁或數(shù)據(jù)庫中組合不同的編碼,因此使用“傳統(tǒng)”編碼方法來支持多語言頁面通常非常困難

Unicode協(xié)會(huì)提供了一個(gè)大的,單字節(jié)字符集,旨在包括所有需要的世界上任何書寫系統(tǒng),包括古老的腳本(如楔形文字,哥特式和埃及的象形文字)的字符,所以統(tǒng)一字符編碼,將其作為Web和操作系統(tǒng)體系結(jié)構(gòu)的基礎(chǔ),并且得到所有主要Web瀏覽器和應(yīng)用程序的支持。當(dāng)前的Unicode字符分為17組編排,每組被稱之為一個(gè)平面(Plane),所以將字符劃分為0-16號(hào)的平面,而每平面擁有65536(即216)個(gè)代碼點(diǎn)即范圍區(qū)間在0x000到0xFFFF之間,而0號(hào)平面就是基本多語言平面(BMP:Basic Mutiingual Plane)。在基本多文本平面上針對(duì)每一種文字或者其補(bǔ)充或者其擴(kuò)展都給出了一個(gè)編碼范圍,比如拉丁文【0000-007F】,拉丁文-補(bǔ)充【0080-00FF】等等。說了這么多,我們只需要記住一點(diǎn)即可:在Unicode字符集中前65536個(gè)代碼點(diǎn)構(gòu)成了基本多語言平面簡(jiǎn)稱BMP,BMP中包含了大多常用的字符,另外Unicode字符集還包含了一百萬個(gè)其他代碼點(diǎn)的位置空間,我們稱之為補(bǔ)充字符。

我們需要區(qū)分字符集、編碼字符集和編碼的概念,字符集或字符串包含可能用于特定目的的字符集,它是支持計(jì)算機(jī)上的西歐語言所需的字符集,與計(jì)算機(jī)完全無關(guān),而編碼字符集是一組用于該唯一的號(hào)碼被分配給每個(gè)字符的字符,有時(shí)候我們將編碼字符集也可稱作為代碼頁,編碼字符集的單位稱為代碼點(diǎn),代碼點(diǎn)值表示字符在編碼字符集中的位置。例如,Unicode編碼字符集中字母á的代碼點(diǎn)為十進(jìn)制225,十六進(jìn)制表示法為0xE1。而字符編碼反映編碼字符集被映射到用于在計(jì)算機(jī)操縱字節(jié)的方式。一個(gè)字符集可以有多種編碼,許多字符編碼標(biāo)準(zhǔn),例如ISO 8859系列中定義的標(biāo)準(zhǔn),都為給定字符使用單個(gè)字節(jié),并且編碼是對(duì)編碼字符集中字符標(biāo)量位置的直接映射。例如,ISO 8859-1編碼字符集中的字母A在第65個(gè)字符位置(從零開始),并且使用值為65的字節(jié)進(jìn)行編碼并以此在計(jì)算機(jī)中表示,對(duì)于ISO 8859-1而言,這將永遠(yuǎn)不會(huì)再改變

但是,對(duì)于Unicode,事情并沒有如此簡(jiǎn)單,盡管Unicode編碼字符集中字母á的代碼點(diǎn)始終為225(十進(jìn)制),但在UTF-8中,它在計(jì)算機(jī)中由兩個(gè)字節(jié)表示,換句話說,在此字符的編碼字符集值和編碼值之間不是簡(jiǎn)單的一對(duì)一映射,另外,在Unicode中,針對(duì)同一字符可以有多種編碼的方式。例如,字母á可以用一種編碼形式的兩個(gè)字節(jié)表示,而用另一種編碼形式的四個(gè)字節(jié)表示。可以與Unicode一起使用的編碼形式稱為UTF-8,UTF-16和UTF-32。

如何解決MySQL對(duì)JSON類型UTF-8編碼導(dǎo)致中文亂碼問題

UTF-8使用1個(gè)字節(jié)表示ASCII集中的字符,使用2個(gè)字節(jié)表示其他幾個(gè)字母塊中的字符,使用3個(gè)字節(jié)表示BMP的其余部分,補(bǔ)充字符使用4個(gè)字節(jié)。UTF-16對(duì)BMP中的任何字符使用2個(gè)字節(jié),對(duì)補(bǔ)充字符使用4個(gè)字節(jié)。UTF-32對(duì)所有字符使用4個(gè)字節(jié)?;径嗾Z言平面對(duì)應(yīng)代碼點(diǎn)存儲(chǔ)的是常用字符,上述針對(duì)不同字符在其對(duì)應(yīng)代碼點(diǎn),然后計(jì)算出該字符的16進(jìn)制的字符串,舉個(gè)栗子,將【好】字進(jìn)行UTF-8編碼看看該字符的字節(jié)值和字節(jié)數(shù),如下:

如何解決MySQL對(duì)JSON類型UTF-8編碼導(dǎo)致中文亂碼問題

如何解決MySQL對(duì)JSON類型UTF-8編碼導(dǎo)致中文亂碼問題

到此我們大概了解完了字符編碼,接下來我們?cè)俅位氐缴弦还?jié)的問題,上一節(jié)將我姓名作為JSON存儲(chǔ)到數(shù)據(jù)庫中去,但是最終獲取數(shù)據(jù)時(shí),將出現(xiàn)亂碼,因?yàn)槠浔砭幋a為utf8,最終將表編碼修改為utf8mb4才好使,為啥utf8就不行呢?通過上述對(duì)utf8的定義最多可以有4個(gè)字節(jié),支持補(bǔ)充字符,所以MySQL根本就沒有實(shí)現(xiàn)標(biāo)準(zhǔn)的utf8編碼,換句話說只是部分實(shí)現(xiàn)了utf8編碼,MySQL中的utf8又名為utf8mb3,也就是一個(gè)字符最多可通過3個(gè)字節(jié)表示且包含BMP字符,而不包含補(bǔ)充字符。所以無論是我的姓還是名雖然是3個(gè)字節(jié),但是并非常用BMP字符導(dǎo)致。但是針對(duì)列類型為JSON類型,事實(shí)是對(duì)于獲取中文真的會(huì)亂碼嗎?上文我用到的MySQL版本為5.7+,如下:

如何解決MySQL對(duì)JSON類型UTF-8編碼導(dǎo)致中文亂碼問題

接下來我們利用MySQL 8.0再來進(jìn)行測(cè)試發(fā)現(xiàn)不會(huì)亂碼,創(chuàng)建類和表配置編碼如下:

如何解決MySQL對(duì)JSON類型UTF-8編碼導(dǎo)致中文亂碼問題

如何解決MySQL對(duì)JSON類型UTF-8編碼導(dǎo)致中文亂碼問題

如何解決MySQL對(duì)JSON類型UTF-8編碼導(dǎo)致中文亂碼問題

如何解決MySQL對(duì)JSON類型UTF-8編碼導(dǎo)致中文亂碼問題

如何解決MySQL對(duì)JSON類型UTF-8編碼導(dǎo)致中文亂碼問題

如何解決MySQL對(duì)JSON類型UTF-8編碼導(dǎo)致中文亂碼問題

隨著移動(dòng)端的興起,有了表情的出現(xiàn),所以從MySQL 5.5.3開始,引入utf8mb4字符集每個(gè)字符最多可使用4個(gè)字節(jié),支持補(bǔ)充字符,對(duì)于BMP字符,utf8 [utf8mb3]和utf8mb4具有相同的存儲(chǔ)特征:相同的代碼值,相同的編碼,相同的長(zhǎng)度,對(duì)于補(bǔ)充字符,utf8 [utf8mb3]根本無法存儲(chǔ)該字符,而utf8mb4需要4個(gè)字節(jié)來存儲(chǔ)它,由于utf8 [utf8mb3]根本無法存儲(chǔ)字符,因此在utf8 [utf8mb3]列中沒有任何補(bǔ)充字符。接下來我們?cè)卺槍?duì)JSON類型配置為utf8編碼的情況下,我們來插入表情,此時(shí)會(huì)發(fā)現(xiàn)也是可以的。我們是可以獲取對(duì)應(yīng)字符的字節(jié)數(shù),比如如下哭笑不得的表情為4個(gè)字節(jié):

如何解決MySQL對(duì)JSON類型UTF-8編碼導(dǎo)致中文亂碼問題

如何解決MySQL對(duì)JSON類型UTF-8編碼導(dǎo)致中文亂碼問題

如何解決MySQL對(duì)JSON類型UTF-8編碼導(dǎo)致中文亂碼問題

其實(shí)針對(duì)JSON類型獲取數(shù)據(jù)亂碼的情況早就有人提出過相關(guān)bug,詳見地址《https://bugs.mysql.com/bug.php?id=81677》,不過官方一直沒有任何回復(fù),至少通過上述測(cè)試出來的結(jié)果對(duì)于utf8存儲(chǔ)表情也可以,到底具體情況咋回事,我們還是看看8.0版本以對(duì)utf8編碼描述為準(zhǔn),詳情請(qǐng)見《https://dev.mysql.com/doc/refman/8.0/en/charset-unicode.html》,對(duì)于utf8編碼的描述依然還是最多可存儲(chǔ)3個(gè)字節(jié),如下:

如何解決MySQL對(duì)JSON類型UTF-8編碼導(dǎo)致中文亂碼問題

別忘記,還有注意:utf8[utf8mb3]字符集已被棄用,并會(huì)在將來的MySQL版本中移除,請(qǐng)改用utf8mb4,盡管utf8當(dāng)前是utf8mb3的別名,但在某些時(shí)候utf8將成為對(duì)utf8mb4的引用,為避免對(duì)utf8的含義含糊不清,請(qǐng)考慮為字符集引用顯式指定utf8mb4而不是utf8。

所以到此我們已明了,針對(duì)8.0版本中的utf8編碼雖說最多可支持3個(gè)字節(jié),但是,會(huì)將utf8成為utf8mb4的引用,如此就不難理解為何上述將表配置為utf8編碼時(shí),對(duì)于JSON類型的不在常用BMP字符進(jìn)行數(shù)據(jù)存儲(chǔ)和表情皆沒問題

關(guān)于如何解決MySQL對(duì)JSON類型UTF-8編碼導(dǎo)致中文亂碼問題問題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識(shí)。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI