《MYSQL教程MySQL亂碼問題終極指南》要點:
本文介紹了MYSQL教程MySQL亂碼問題終極指南,希望對您有用。如果有疑問,可以聯系我們。
MYSQL數據庫mysql的字符集設置眾多,從客戶端到連接到結果集,從服務器到庫到表到列,都可以設置字符集,靈活很強大,但就是很容易出問題,如果不了解其機制,很容易就出現亂碼問題.
MYSQL數據庫為了讓大家盡量在工作中少受或者不受亂碼的困擾,這里我結合之前其它同學在論壇的發帖,并結合自己的理解和實踐,詳細分析總結了一下,以饗各位看官.
MYSQL數據庫關于字符集和亂碼的基礎知識這里就不詳細說明了(請自行搜索),但有一個問題需要特別強調一下:亂碼是怎么產生的?
這個問題相信很多同學都是模棱兩可,或者沒有認真想過,反正理解就是”字符編碼“不對導致亂碼,但沒有真正想過為什么”字符編碼“會導致亂碼.
答案其實很簡單:“轉換導致亂碼”!
根據這個原則來判斷,各種情況就很簡單了:
MYSQL數據庫1)數據傳送過程中不會導致亂碼
2)數據存儲不會導致亂碼
3)數據輸入和輸出(包括顯示)可能導致亂碼
4)數據接收和發送可能導致亂碼
MYSQL數據庫更詳細的解釋:轉換導致亂碼是指本來是A字符集的數據被當成了B字符集進行解析,而不是說正確的A字符集轉換為B字符集.
例如:如下mysql字符處理機制流程圖中,mysql客戶端發送的實際上是2個gbk字符(4字節),但character_set_connection
設置了utf8,于是mysql服務器將收到的4字節gbk數據按照utf8解析,得到1個中文字符+1個字節,這時就產生亂碼了;
MYSQL數據庫如果character_set_connection 設置為gbk,mysql服務器收到數據后按照gbk解析,得到兩個正確的中文,然后再轉換為這兩個中文對應的utf8編碼,這就不會產生亂碼.)
MYSQL數據庫【mysql的字符處理機制】
MYSQL數據庫詳細的處理機制如下圖:
MYSQL數據庫
MYSQL數據庫我們模擬一下一條數據從插入到讀取的處理流程,看看在整個流程中,字符集是如何輾轉騰挪的.
【插入流程】
1. 客戶端設定了自己的編碼(character_set_client),接收用戶的輸入;
2. 客戶端將用戶的輸入“轉換”成連接的編碼(character_set_connection) =====> 第一次轉換
3. 客戶端將轉換后的數據發送給服務器;? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? =====> 傳輸不會導致編碼轉換
4. 服務器收到客戶端的數據,再判斷數據列的字符集,進行字符轉換? ?? ? =====> 第二次轉換
5. 服務器將數據存儲(例如磁盤)? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? =====> 存儲不會導致編碼轉換??
MYSQL數據庫【讀取流程】
略去前面的sql語句處理流程,從數據讀取開始
1. 服務器從存儲(例如磁盤)讀取數據? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?=====> 存儲不會導致編碼轉換,因此從存儲讀取也不需要
2. 服務器判斷當前連接返回結果的字符集(character_set_results),
? ?將讀取的數據轉換為結果集要求的數據? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? =====> 逆向的第一次轉換,對應正向的第二次編碼轉換
3. 服務器將數據發送給客戶端? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???=====> 傳輸不會導致編碼轉換
4. 客戶端收到服務器的數據,根據客戶端的字符集(character_set_client)進行編碼轉換? ?? ?? ? =====> 逆向第二次轉換,對應正向第一次編碼轉換
5. 客戶端顯示數據? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?=====> 你能看到亂碼的時候
MYSQL數據庫有了這個流程,我們就很容易定位亂碼可能產生的地方,以及產生亂碼的字符集配置究竟是哪個了.
理想的情況是整個流程中,所有涉及字符轉換的地方都不需要轉換,這樣就不會產生亂碼了.
MYSQL數據庫有了上面的理論分析后,我們再結合一個亂碼的抓包實例,加深理解,其中有一些問題,請大家思考一下,看看是否真的理解了.
MYSQL數據庫環境:
+--------------------------+-----------------------------------------------------+
| Variable_name??????????? | Value?????????????????????????????????????????????? |
+--------------------------+-----------------------------------------------------+
| character_set_client???? | latin1????????????????????????????????????????????? |
| character_set_connection | latin1????????????????????????????????????????????? |
| character_set_database?? | utf8??????????????????????????????????????????????? |
| character_set_filesystem | binary????????????????????????????????????????????? |
| character_set_results??? | latin1????????????????????????????????????????????? |
| character_set_server???? | utf8??????????????????????????????????????????????? |
MYSQL數據庫測試語句是插入一個中文字符“你”,其utf8編碼為"0xE4 0xBD 0xA0",
MYSQL數據庫1. latin1發送包?
MYSQL數據庫
MYSQL數據庫思考一下1:為什么客戶端和連接都設置了latin1,但最終發送的是正確的utf8編碼呢?
MYSQL數據庫2. latin1接收包?
MYSQL數據庫
MYSQL數據庫思考一下2:為什么接收到的還是正確的utf8編碼?
MYSQL數據庫3. latin1不顯示亂碼?
MYSQL數據庫
MYSQL數據庫思考一下3:為什么latin1顯示了正確的utf8字符?
MYSQL數據庫4. utf8接收包?
MYSQL數據庫
MYSQL數據庫思考一下4:為什么連接的字符集和數據庫的字符集設置成一樣了,接收的數據反而不是utf8了?(請與latin1接收數據包對比)
MYSQL數據庫5. utf8顯示包
MYSQL數據庫
MYSQL數據庫思考一下5:為什么連接的字符集和數據庫的字符集設置成一樣了,顯示反而亂碼了??
MYSQL數據庫怎么樣,上面的思考題是否都有答案了,如果沒有,相信下面這幅圖能夠幫助你:
MYSQL數據庫這個抓包案例的字符變化圖解:
MYSQL數據庫
MYSQL數據庫附:mysql字符編碼操作技巧
【查看字符集設置】
MYSQL數據庫
mysql> show variables like '%char%';
+--------------------------+-----------------------------------------------------+
| Variable_name | 說明 |
+--------------------------+-----------------------------------------------------+
| character_set_client | 客戶端字符集 |
| character_set_connection | 當前連接字符集 |
| character_set_database | 數據庫字符集 |
| character_set_filesystem | 文件系統字符集,不要修改,使用binary即可 |
| character_set_results | 返回結果集字符集 |
| character_set_server | 服務器默認字符集,當數據庫、表、列沒有設置時, |
| | 默認使用此字符集 |
| character_set_system | 固定為utf8 |
+--------------------------+-----------------------------------------------------+
MYSQL數據庫【修改字符集設置】
服務器的配置在服務器建立的時候就由DBA設置好了,不推薦后續再改
通過SET NAMES utf8命令同時設置character_set_client/character_set_connection/character_set_results的字符集
建議所有配置都設置成utf8
MYSQL數據庫【問題答案】
MYSQL數據庫思考一下1:為什么客戶端和連接都設置了latin1,但最終發送的是正確的utf8編碼呢?
客戶端設置了latin1,而我的語句是從notepad++中寫好的,是utf8格式的;
中文utf8是3個字節,而latin1是按照單個字節解析的,雖然進行了轉換,但不會導致二進制內容的變化,但實際上mysql客戶端認為我輸入了3個latin1字符;
如果客戶端設置的編碼是2個字節的gbk,這時轉換就會發生亂碼,utf8的3個字節會被轉換為1個gbk字符(可能是亂碼,也可能不是亂碼)加上一個西歐字符(小于128就是英文,大于128就是其它西歐文)
MYSQL數據庫思考一下2:為什么接收到的還是正確的utf8編碼?
這是因為mysql服務器從將數據從“列”的編碼(utf8)轉換為latin1了,而列存儲的數據并不是真正的utf8的中文“你”對應的"0xe4 0xbd 0xa0",
而是后面抓包看到的“c3a4 c2bd c2a0”(6個字節),mysql服務器將utf8的c3a4轉換為latin1的0xe4,c2bd轉換為0xbd, c2a0轉換為0xa0
MYSQL數據庫思考一下3:為什么latin1顯示了正確的utf8字符?
因為mysql客戶端收到了mysql服務器轉換后的"0xe4 0xbd 0xa0",并把這個數據當做latin1的3個字符處理,然后拋給終端(我的是SecureCRT),
SecureCRT又把這三個latin1當做uft8處理,結果中文的“你”就顯示出來了.
MYSQL數據庫思考一下4:為什么連接的字符集和數據庫的字符集設置成一樣了,接收的數據反而不是utf8了?(請與latin1接收數據包對比)
字符集都一樣的情況下,整個流程中不需要進行編碼轉換,直接將存儲的“c3a4 c2bd c2a0”返回給客戶端
MYSQL數據庫思考一下5:為什么連接的字符集和數據庫的字符集設置成一樣了,顯示反而亂碼了?
參考思考4,客戶端收到數據后也直接拋給終端顯示,終端認為是兩個utf8字符,并且找到了對應字符并顯示,但我們看不懂,所以知道是亂碼了,但這兩個字符顯示并沒有錯,如果真正找不到字符,可能會顯示問號或者字符集規定的缺省符號.
MYSQL數據庫以上就是關于MySQL亂碼問題大集合,希望能夠幫助大家解決MySQL亂碼問題,謝謝大家的閱讀.
轉載請注明本頁網址:
http://www.snjht.com/jiaocheng/1241.html