您現在的位置是:首頁 > 明星首頁明星

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

由 IT學習日記 發表于 明星2021-08-20
簡介1、MySQL支援的字符集查詢命令:show charset或者character set like '字符集的名稱'(一)、透過下圖可知,MySQL資料庫預設支援41種字符集,下圖關鍵詞的含義:1、Charset列為字

漢字內碼佔幾個位元組

種一棵樹最好的時候是十年前,其次是現在!加油吧,騷年!

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

一、前言

大家好,我是小誠,又到了愉快的學習時間,本篇章主要給大家介紹的是資料庫中字符集和比較規則的知識,由淺入深,理解亂碼產生的原因,

文章稍微有點長,如果大家沒時間看可以先收藏,後面再抽時間來複習

安利一下,如果在學習過程中遇到任何問題,都可以私信我哦!更多文章,大家可以點選《從0到1-全面深刻理解MySQL系列》瞭解!

《從0到1-全面深刻理解MySQL系列》系列文章會持續更新,

感興趣的小夥伴可以關注我,,一起加油,一起進步!,如有幫助,不要忘記一鍵三聯哦,ღ( ´・ᴗ・` )比心!

二、帶著問題學習

在文章開始前,大家可以先考慮幾個問題,這樣方便更快理解文章的知識點,下面的問題都會在文章中找到答案哦!

1、字符集、編碼、解碼的概念是否真的理解?

2、常見的字符集如utf-8,gbk等存在什麼差異?

3、資料庫中如何設定字符集型別?

4、什麼是比較規則,資料庫中如何設定比較規則型別?

5、什麼是亂碼,為什麼會產生亂碼?

6、MySQL中UTF-8、UTF-8mb3、UTF-8mb4有什麼區別?

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

三: 字符集

字符集的產生

學習過計算機的都知道,計算機只能儲存二進位制的資料即0和1

,那平常我們使用電腦中展示的表情包、字串等資料計算機是如何識別,進行儲存的呢?

顯而易見,是建立非二進位制資料(如:表情包、字串)和二進位制資料(0和1)之間的對映關係,透過它們的對映關係,我們能夠進行相互轉換

,當儲存到計算機中時則轉換成對應的二進位制資料,當需要在電腦展示時則轉換成非二進位制資料。但是,建立這種對映關係我們需要考慮哪些問題呢?

如需建立兩者的對映關係,我們需要考慮以下的問題:

1、確定建立對映的字元範圍即:哪些字元是需要和二進位制資料建立對映?

2、如何實現兩者之間的對映即:對映的規範是什麼?

其實,上面的這兩個問題我們平常的計算機使用者是無法接觸到的,字符集的制定是有專門的組織如ISO/IEC等來進行制定的,制定後經過實踐是可行的才會應用到計算機中。

雖然,這個過程我們是無法參與,但是,我們要知道它們產生的原因,因為不同區域是使用不同的語言進行交流,視覺上的體現就是使用不同的符號進行溝通,如美國,英國等地方就是使用26個字母進行交流,而我們國家則會存在更加複雜的各式各樣的文字,

所以,字符集是為了適應不同區域透過計算機之間完成交流而產生的。

有關字符集的概念

在更進一步認識字符集之間,需要了解一些相關概念。

1。1、字符集

可以理解為某些字元組成的一個集合,集合中由哪些字元組成是由制定這個字符集的協會來決定。

1。2、字符集與字元編碼的區別

字元編碼則是:將字符集中的字元對映為特定的位元組或者位元組序列,它表示的是一種規則。

通常特定的字符集採用特定的編碼方式(即一種字符集對應一種字元編碼,如: ASCII、ISO-8859-1、GB2312、GBK都是表示了字符集又表示了對應的字元編碼,但Unicode字符集是特例,它對應的字元編碼有:UTF-8、UTF-16、UTF-32)

如:我們自定義一個my字符集和字元編碼,它的一個規則如下:

1、包含的字元:‘h’、‘l’,‘o’,‘e’

2、編碼規則: 一個字元需要一個位元組編碼(

注: 1byte(位元組) = 8bit,1bit對應的就是一個0或者1

),則字元和位元組的對映關係如下:

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

透過上面的對映關係我們知道my字符集可以組成許多不一樣的字元,具體如下:

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

1。3、編碼

將一個字元對映成二進位制資料的過程叫做編碼,如:'a' => 0000 00001

1。4、解碼

將一個二進位制資料對映成一個字元的過程叫做解碼,如:0000 00001 => 'a'

1。5、舉例說明編碼與解碼的過程

透過上面的基礎規則學習,我們已經對字符集、編碼、解碼等基礎知識有了基本的認識。現在我們就透過圖形化來舉一個例子更加形象理解的這些知識(以:ASCII字符集為準,用我們程式設計入門的最常見的字串:hello world為例子)

編碼:

在螢幕輸入文字 -> 根據指定編碼型別 -> 將輸入的文字編碼成計算機能夠識別的二進位制數 -> 計算機儲存編輯成的二進位制數值

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

解碼:

計算機讀取儲存的二進位制數值 -> 根據指定的解碼型別解碼 -> 將二進位制數值解碼成字符集中表達的字元 -> 在螢幕顯示

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

1。6、變長位元組編碼方式

⼀個字元編碼需要的位元組數可能不同的編碼⽅式稱為變長編碼⽅式

,比如GB2312編碼方式,因為GB2312字符集相容了ASCII字元,所以當一個字串中有的字元屬於ASCII字符集中的字元時,它編碼時需要佔用的位元組數為1,如果字元屬於ASCII字符集中沒有的,則編碼時需要佔用2個位元組。

舉例說明:

比如字串‘日b’,其中‘日’不屬於ASCII字符集中的字元,需要⽤2個位元組進行編碼,假設編碼後的⼗六進製表示為0xCD2,‘u’屬於ASCII字符集的字元,需要⽤1個位元組進⾏編碼,假設編碼後的⼗六進製表示為0x15,所以拼合起來就 是0xCD215。

二、常見的字符集

2。1、常見的字符集類別

ASCII、GB2312、Unicode、GBK等

(一)ASCII字符集和ASCII編碼

ASCII字符集:

全稱《美國資訊交換標準程式碼》,主要用於顯示現代英語和其它西歐語言,主要包括:可顯示字元(英文字母、阿拉伯數值、標點符號)、以及控制字元(回車、換行、退格等特殊字元)。

ASCII編碼:

使用一個位元組編碼,美國定製的交換標準,目的是將ASCII字符集包含的字元轉換成計算機能夠識別的二進位制(0和1)

,它是最通用的資訊交換標準,到目前為止總共定義了128個字元。

ASCII編碼缺點:

只能顯示26個基本拉丁字母、阿拉伯數目字和英式標點符號,因此只能用於顯示現代美國英語(而且在處理英語當中的外來詞如naïve、café、élite等等時,所有重音符號都不得不去掉,即使這樣做會違反拼寫規則),而且對其他的語言支援力度也不大,所以現在蘋果也使用Unicode替換ASCII。

(二) ISO 8859-1字符集

別名latin1,使用一個位元組編碼,相容ASCII字符集

,是在ASCII字符集的基礎上⼜擴充了128 個⻄歐常⽤字元(包括德法兩國的字⺟),共收錄256個字元。

(三)GBXXXX字符集

(1)

GB2312字符集:

全稱:《資訊交換用漢字編碼字符集》,剛開始ASCII字符集只包含了阿拉伯數字、字母和一些特殊符號,這個編碼只適用於美國和西方的一些國家,而不適用於使用漢字的國家,

為了使用漢字的國家也能夠和計算機進行溝通,中國國家標準總局釋出了標準號為:GB2312的編碼格式,它適用於漢字處理、漢字通訊等系統之間的資訊交換,除了中國大陸使用外,新加坡等地也採用此編碼。

GB2312字符集共收錄了6763個簡體漢字

,它的收錄包括了拉丁字母、日文平假名等在內的682個全形字元,GB2312編碼可以將GB2312字符集包含的字元轉換成計算機能夠識別的二進位制0和1。

特點:

因為它相容了ASCII字符集,所以在編碼方式上存在多種情況,

如果字元屬於ASCII字符集中的字元的話,則編碼時需要使用1個位元組進行編碼,如果不屬於ASCII字符集,則需要使用2個位元組進行編碼。

(2)

GBK字符集

全稱:《漢字內碼擴充套件規範》,因為GB2312字符集編碼只支援簡體漢字和一些特殊符號,繁體字和一個特殊簡體字都沒有收錄其中,所以微軟針對GB2312做了拓展,

在GBK字符集中收錄了繁體字,並最早在Window95簡體中文版使用。

GBK拓展了GB2312字符集,共收錄了兩萬多個文字,GBK編碼可以將GBK字符集收錄的字元轉換成計算機能夠識別的二進位制0和1。

(3)

GB18030字符集

全稱: 國家標準GB 18030-2005《資訊科技 中文編碼字符集》,因為GBK是由微軟首先制定的,並不屬於國家標準,

所以國家為了相容GBK字符集制定了GB18030字符集,它是中華人民共和國現時最新的內碼字集,除了相容GBK字符集外,還支援GB 13000及Unicode字符集的全部統一漢字。

GB 18030字符集共收錄漢字七萬多個,並且儲存方式採用的是可變長位元組編碼,每個字可以由1個、2個或4個位元組組成。

(四)Unicode字符集

Unicode字符集的出現:

當計算機出現在全球各地時,為了與計算機進行交流,指定了各種各樣的標準如GB232/GBK/GB18030/BIG5的編碼方案,如果只在符合對應標準的地區使用則完全沒有問題,但是如果透過網路與其他的地區進行交流時,

因為各地的編碼的標準都不一樣,就會在轉換中出現"亂碼"現象,為了解決這個問題,Unicode字符集應運而生。

Unicode也稱為:

統一碼/萬國碼/單一碼,它是業界的一種標準,透過它計算機可以實現世界上不同地區數十種文字的顯示,

2005年Unicode就已經收錄了超過十萬個字元,現在由Unicode組織進行管理運作,它收錄地球上能想到的所有字元,⽽且還在不斷擴充。

Unicode編碼系統為表達任意語言的任意字元而設計,它為每種語言中的每個字元設定了統一併且唯一的二進位制編碼,以滿足跨語言、跨平臺進行文字轉換、處理的要求。

Unicode編碼標準現在有三種具體實現,分別是:UTF-8、UTF-16、UTF-32。

(1)

UTF-8字元編碼:

它是實現了Unicode編碼方案的一種可變長字元編碼(定長碼),也是一種字首碼。

它可以用來表示Unicode標準中的任何字元,且其編碼中的第一個位元組仍與ASCII相容,這使得原來處理ASCII字元的軟體無須或只須做少部分修改,即可繼續使用。

UTF-8已經逐漸成為電子郵件、網頁及其他儲存或傳送文字的應用中,優先採用的編碼。

網際網路工程工作小組(IETF)要求所有網際網路協議都必須支援UTF-8編碼。

UTF-8編碼使用一至四個位元組為每個字元編碼

(其中ASCII字符集中的128個字元只佔1位元組,還有附加符文的拉丁文、希臘文等需要2個位元組,其他常用的文字佔用3個位元組,還有極少數的字元佔用4個位元組)。

(2)

UTF-16字元編碼:

它是實現了Unicode編碼方案的一種可變長字元編碼(定長碼)

因為Unicode字符集中收錄了很多字元,但是常用的一般不會超過65535個以外的字元,所以出現了UTF-16(2位元組=16位)。

UTF-16優點:

它在空間效率上比UTF-32高兩倍,因為每個字元只需要2個位元組來儲存(除去65535範圍以外的),而不是UTF-32中的4個位元組。

UTF-16缺點: 不相容ASCII。

(3)

UTF-32字元編碼:

它是實現了Unicode方案的一種定長字元編碼。

它使用4個位元組的數字來表示每個字母、符號,或者表意文字(ideograph)。

優缺點: 使用4個位元組儲存每個字元,效率高,處理速度快(因為不用計算需要幾個位元組進行儲存),但是浪費空間。

(五)字符集知識拓展

更多關於字符集的知識,可以到《全網最全面、全詳細的編碼、解碼知識!!!》檢視。

三、比較規則的產生

透過上文我們知道字符集就是包含了多個字元組合的一個集合,既然存在這樣一個集合,那它們的是如何比較不同字元的大小呢?這裡就需要我們的第二位主角登場了

比較規則: 字符集中字元的一個比較大小的規則,一個字符集中可以存在多個比較規則

。最常見的比較方式就是字元對映後的二進位制比較,英文名也叫binary collation,如:字元a對應的二進位制為0000 0001,字元b對應的二進位制為0000 0010,,則我們可以說在這種規則下字元b大於字元a。

四、MySQL中的字符集和比較規則

透過上面的介紹,大家應該已經對字符集和比較規則的一些概念有了大致的瞭解,下面我們就開始結合MySQL來進行真正的實戰。

4。1、MySQL支援的字符集

查詢命令:

show charset或者character set like '字符集的名稱'

(一)、透過下圖可知,MySQL資料庫預設支援41種字符集,下圖關鍵詞的含義:

1、Charset列為字符集的名稱

2、Default collation列為字符集對應的預設比較規則(因為一種字符集是可以存在多種比較規則的)

3、Maxlen列則表示這種字符集編碼(表示)一個字元時最多需要多少個位元組。

(二)、常用的字符集一個字元編碼需要的最大位元組數

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

4。2、MySQL中utf-8和utf-8mb4的區別

在上面的截圖中,可能有人會有疑問,為什麼mysql會支援兩種utf-8(即utf-8和utf-8mb4)型別的編碼?它們之間存在什麼區別?

我們在上面介紹Unicode字符集時有說到,其實utf-8,utf-32都是屬於Unicode字符集的一種編碼方案,utf-8編碼方案表示一個字元需要1~4個位元組,但是,

在實際生活中常用的字元實際上只需要3個位元組即可表示,在資料庫中,表示字元的大小會影響到資料存取的效能,所以MySQL資料庫的設計者就定義類utf-8和utf-8mb4兩套方案。

1、utf-8也叫utf-8mb3: 代表一個字元只需要1~3個字元。

2、utf-8mb4: 代表一個字元需要使用1-4個字元,也就是我們平常說的真正的utf-8編碼。

區別:

在MySQL資料庫中,utf-8是utf-8mb3的別名,它是使用1~3個位元組來表示一個字元的,如果需要使用4個位元組表示一個字元的,如儲存emoji表情包,需要使用utf-8mb4編碼方案。

4。3、MySQL支援的比較規則

查詢命令:

show collation like '比較規則名(可以模糊查詢)'

(一)、由下圖可知,現在MySQL資料庫支援222種比較規則,每種字符集可能存在多種比較規則,它們的規律如下:

1、比較規則都是以字符集的名稱開頭,如下圖2中的utf-32比較規則都屬於utf-32字符集。

2、下劃線的第二個單詞表示的是該比較規則是使用於哪種語言,如:utf-32_spanish_ci則表示使用西班牙語的規則比較,utf-32_general_ci則表示是一種通用的比較規則。

3、結尾的單詞表示是否區分不同語言中的重音、大小寫等策略,常見的結尾詞語含義如下:

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

每種字符集對應可能存在多種比較規則,所以在不指定具體比較規則的時候,字符集會有自己預設的一個比較規則

,使用show collation查詢出來的比較規則中,default列值為yes的表示屬於該字符集的預設比較規則,如上圖中utf-32的比較規則就是utf32_general_ci。

五、MySQL中的字符集和比較規則的應用

MySQL資料庫中,支援4個層級的方式來設定資料庫的字符集和比較規則,

範圍從大到小分別是: MySQL伺服器級別、資料庫級別、表級別、列級別。

5。1、檢視/設定MySQL伺服器級別字符集和比較規則

MySQL保留了以下兩個關鍵字來設定伺服器級別的字符集型別和比較規則,具體含義如下:

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

我們可以透過下面的兩條命令來查詢MySQL伺服器級別預設的字符集型別和比較規則

1、查詢預設的字符集型別: shwo variabkes like 'character_set_server';

2、查詢預設的比較規則型別: shwo variabkes like'collation_server';

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

如果我們想修改預設的伺服器級別的字符集型別和比較規則,可以在MySQL啟動的配置檔案或者直接透過set對應的變數達到修改的目的。

方式1:

修改MySQL啟動配置檔案配置(直接到MySQL安裝路徑下找my。ini)然後新增以下的屬性即可

character_set_server=utf-32 collation_server=utf-32_chinese_ci

  方式2:

連線資料庫後直接透過set設定這兩個變數的值,但是這個設定只針對本次客戶端連線,如果退出了連線則會還原預設的,下一次連線還是系統之前預設的值。

總結:

上面我們說到,每個字符集都有一個預設的比較規則,它們之間是相互存在聯絡的,無論我們修改它們兩個中的哪一個,另外一個也會跟著改變既:

只修改字符集,則⽐較規則將變為修改後的字符集預設的⽐較規則,只修改⽐較規則,則字符集將變為修改後的⽐較規則對應的字符集。

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

5。2、檢視/設定資料庫級別字符集和比較規則

資料庫中存在以下的兩個變數用於描述資料庫的字符集和比較規則,但是它們都是隻讀的,沒法透過修改這兩個變數的值來修改資料的字符集和比較規則,

想要修改資料庫的字符集和比較規則,需要在建立或者修改資料庫的時手動指定character set和collation變數的值,如果不指定的話,則預設使用伺服器級別的字符集和比較規則。

指定資料庫字符集和比較規則的語法:

// 建立資料庫時指定字符集和比較規則create database 資料庫名 [[default] character set 字符集名稱] [[default] collate ⽐較規則名稱]; // 修改資料庫的字符集和比較規則alter database 資料庫名 [[default] character set 字符集名稱]

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

資料庫字符集和比較規則變數:

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

5。3、檢視/設定表級別字符集和比較規則

在建立或者修改資料表的時候,我們可以根據自己需要去修改資料表對應的字符集和比較規則,但是如果不指定的話,則預設使用資料庫級別的字符集和比較規則,具體的語法如下:

// 建立資料表時指定字符集和比較規則create table 表名 (列的資訊) [[default] character set 字符集名稱] [collate ⽐較規則名稱]] // 修改資料表的字符集和比較規則alter table 表名 [[default] character set 字符集名稱] [collate ⽐較規則名稱]

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

5。4、檢視/設定列級別字符集和比較規則

在建立或者修改表中欄位的時候,我們可以根據自己需要去指定表中列的字符集和比較規則,但是如果不指定的話,則預設使用表級別的字符集和比較規則,具體的語法如下:

// 建立資料表時指定某列的字符集和比較規則create table 表名( 列名 欄位型別 [character set 字符集名稱] [collate ⽐較規則名稱], 。。。 );// 建立資料表時指定某列字符集和比較規則alter table 表名 modify 列名 欄位型別 [character set 字符集名稱] [collate ⽐較規則名稱];

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

5。5、知道字符集後有什麼作用

透過上面的學習,我們可以準確的知道某個資料庫、某個表、某個欄位對應的字符集型別和比較規則,

我們就可以預估出儲存在資料庫中一條資料佔用的大小,這樣對我們進行最佳化有一定幫助(因為網路傳輸的頻寬是有限制的,一次如果查詢太多資料,查詢的效能會受到影響

,透過預估每條資料佔用的儲存時間,可以幫助我們進一步確定返回資料條數的限制,是否需要分頁等問題)。

如demo表中name欄位使用的字符集是gbk,,儲存的資料如下,根據gbk字符集儲存資料佔用的位元組數最大為2可知(

上文介紹過,可以使用:show charset命令檢視資料支援的字符集和它佔用的位元組數

),在demo表中下面這條資料佔用的儲存空間為6個位元組,如果列的字符集為utf-8則儲存空間為9個位元組。

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

5。6、小結

根據需要我們進行MySQL的服務級別、資料庫級別、資料表級別、列級別進行設定字符集和比較規則,

如果是直接使用語句進行修改的話則只對本次連線起作用,退出連線後又恢復到預設的字符集和比較規則,如果想要程式設計預設的,則可以直接在mysql的配置檔案新增對應的變數設定即可。

一個字符集可以存在多種比較規則,所以每種字符集都會有一個預設的比較規則(可以使用show charset命令檢視),

因為字符集和比較規則是相互聯絡的,所以只修改字符集,則⽐較規則將變為修改後的字符集預設的⽐較規則,只修改⽐較規則,則字符集將變為修改後的⽐較規則對應的字符集

服務級別、資料庫級別、資料表級別、列級別的字符集和比較規則的範圍是從大到小的,所以它們之間有以下的規則:

如果建立或修改資料庫時沒有顯式的指定字符集和⽐較規則, 則該資料庫預設⽤伺服器的字符集和⽐較規則

如果建立或修改表時沒有顯式的指定字符集和⽐較規則,則該 表預設⽤資料庫的字符集和⽐較規則

如果建立或修改列時沒有顯式的指定字符集和⽐較規則,則該列預設⽤表的字符集和⽐較規則

六、MySQL中客戶端與服務端之間字符集的使用

6。1、亂碼的產生

瞭解了字符集和編碼方案知識後,我們知道不同的字符集有不同的編碼,不同的編碼方案佔用的位元組數也是不一樣的,如果操作不當,就會出現讓人無法理解的後果(亂碼),總結起來,出現亂碼的情況以下兩種:

1、編碼過程和解碼過程使用的編碼方式不一致

。試想一下,如果你跟棒子交流說的是漢語,棒子卻用韓語字典查詢翻譯,最後棒子能夠懂你的意思?很明顯,如果編碼和解碼使用的方式不同,最後得到的結果會是南轅北轍。

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

2、編碼/解碼對應的字符集不存在對應的字元

。比如ASCII編碼中只包含有128個字元,沒有繁體字,如果你使用ASCII編碼方案去解碼繁軆字,最後能夠得到正確結果?很明顯,結果得到的也是我們無法理解的一些字串。

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

6。2、字符集轉換

一個字串從一種字符集型別轉換成另外一種字符集

。如字串“菜雞”,編碼型別屬於utf-8,在utf-8編碼中對應的二進位制為0000 0001,在gbk編碼中對應的二進位制為0000 1000,要想轉換成gbk字符集中的字元則需要進行以下兩步操作:

1、先將字串“菜雞”按照gbk字元編碼方案解碼成為對應的二進位制既0000 1000。

2、然後再按照gbk的編碼方案編碼成對應的字串,此時得到的“菜雞”字串就屬於gbk字符集中的一個字串。

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

6。3、MySQL中客戶端與服務端之間字符集的轉換

在MySQL中,客戶端與服務端之間的請求響應最終的體現實際上就是字元序列

。客戶端將傳送的內容根據編碼方式編碼成對應的位元組序列,服務端接收後並進行一系列處理,然後將結果根據對應的編碼方式編碼並返回給客戶端。

在開始講解客戶端與服務端字符集轉換之前,需要先了解一些關於MySQL服務端編碼的概念,如下

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

查詢命令: show variables like 'character_set%'

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

下面讓我們先來看下官方文件是如何描述客戶端和服務端通訊時字符集的轉換的:

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

單單看官方文件,可能比較抽象,下面我們透過具體的圖片來了解它們之間轉換的具體步驟:

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

總結起來就是分為以下的五個步驟:

1、客戶端將SQL語句按照character_set_client字符集對應的編碼方案編碼成位元組序列,然後傳送給服務端。

2、服務端接收到客戶端傳送的位元組序列,將它透過character_set_connection字符集對應的編碼方法進行編碼,生成新的位元組序列。

3、因為表中的列也有自己的字符集型別,且它的優先順序是更高,所以需要將第2步的位元組碼再編碼成列對應字符集的位元組序列,然後去匹配具體的資料。

4、將匹配到的資料按照character_set_results字符集對應的編碼方案編碼成位元組序列,並返回給客戶端。

5、客戶端接收到服務端響應的位元組序列,按照character_set_client對應的字符集編碼型別解碼成對應的字元,展示到螢幕上,到此為止,一次請求和響應成功結束。

6。4、MySQL中客戶端與服務端間字符集轉換的一些疑問

問題1:看到這裡大家肯定會有疑問了,一次請求就要進行這麼多次編碼,有沒有這個必要呢?

答案是肯定的,因為character_set_xxx這三個變數是可以設定為session級別和全域性級別的,因此不同的客戶端可能會不同的編碼型別,必須有對應的引數來適應不同的型別,且表中的欄位也有字符集型別,優先順序更高,所以需要經過對應的編碼和解碼才能實現資料的轉換。

問題二: 為什麼有了character_set_client還要有character_set_connection,直接將character_set_client對應的位元組序列轉換成表中的列對應字符集位元組序列不行?

答案:不行,因為MySQL官網說了,character_set_connection變數對應的字符集是要用於字串字面值的轉義的。

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

問題三: 什麼是字串字面值?

一個字串字面值就是兩個雙引號之間的字元序列,如"hello world"

,上面說到的character_set_connection的作用就是用來轉義這個字串字面值的,如:select length(“我愛你”),如果character_set_connection是utf-8mb3的話則會返回3,如果是utf-32的話則會返回12,也就是說它是根據不同的字符集型別有不同的轉義。

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

小結

1、通常來說,character_set_client、character_set_connection,character_set_results這三個變數的值都是保持一致的,這個就可以避免不同編碼型別之間的轉換。

2、如果我們直接在連線服務端的時候使用set命令設定這三個變數的值,那它只針對本次連線(會話級別),退出本次連線後又會恢復預設的值。使用: 【set names = 字符集型別】可以一次設定這三個變數的值。

3、如果想修改這三個變數的值為全域性級別的,可以在mysql的配置檔案my。ini中新增:default-character-set=字符集編碼(如:utf-8)或者啟動mysql客戶端時指定這個引數,則可以修改它預設設定的值。

七、比較規則的使用

講完字符集之間的關係,我們來講點輕鬆的,比較規則的使用,相信排序這個功能大家沒少用吧,

平常我們都只是直接預設使用order by欄位名,資料庫就返回了排序好的資料給我們

(如果沒有學習過資料庫的也可以看看,後續會進行資料庫語法的講解),你知道這個過程實際上是使用了哪個比較規則,如果需求變動有特殊的要求該怎麼處理?

平常我們使用的最多的就是UTF-8字符集,這裡就透過UTF-8字符集來看比較規則的實際應用。

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

透過上圖可以發現,預設是按照字典的順序進行排序,如果我們有個需求需要根據轉換之後的二進位制進行排序呢,就該使用到我們上面介紹的修改字符集的比較規則來完成了。

1、透過show collation like '需要查詢的比較規則或者字符集名'查詢某種字符集支援的比較規則。

2、使用: ALTER TABLE 表名 MODIFY 列名 字串型別 [CHARACTER SET 字符集名稱] [COLLATE ⽐較規則名稱];

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

「建議收藏」萬字長文實戰-帶你剖析MySQL亂碼、字符集和比較規則

相信經過上面的學習,下次專案經理再給你提供奇葩排序,心裡有底了吧!(先給錢,再加需求)!

參考資料

《mysql是怎樣執行的》

《全網最全的編碼知識》

寫在最後

默默地說一句,能堅持看到最後的都是牛逼的人,為你們點贊!

相信此時你再回頭去看前面的五個問題,心裡應該知道答案是什麼了吧,帶著問題學習是否讓你更加有效率?

肝了兩天,終於完成這篇文章,為了兄弟們方便看,又花了半天進行排版,不多說,都在字裡

,由於個人水平有限,可能在文章中存在一些缺漏,如有發現,歡迎留言或者私信討論。

如果覺得文章對你有幫助,不要忘記掃碼關注和一鍵三連哦,你的支援是我創作更加優質文章的動力,感謝你的閱讀