程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> MYSQL數據庫 >> MySQL綜合教程 >> MySQL亂碼成績最終指南

MySQL亂碼成績最終指南

編輯:MySQL綜合教程

MySQL亂碼成績最終指南。本站提示廣大學習愛好者:(MySQL亂碼成績最終指南)文章只能為提供參考,不一定能成為您想要的結果。以下是MySQL亂碼成績最終指南正文


mysql的字符集設置浩瀚,從客戶端到銜接到成果集,從辦事器到庫到表到列,都可以設置字符集,靈巧很壯大,但就是很輕易出成績,假如不懂得其機制,很輕易就湧現亂碼成績。

為了讓年夜家盡可能在任務中少受或許不受亂碼的困擾,這裡我聯合之前其它同窗在服裝論壇t.vhao.net的發帖,並聯合本身的懂得和理論,具體剖析總結了一下,以飨列位看官。

關於字符集和亂碼的基本常識這裡就不具體解釋了(請自行搜刮),但有一個成績須要特殊強調一下:亂碼是怎樣發生的?
這個成績信任許多同窗都是含糊其詞,或許沒有賣力想過,橫豎懂得就是”字符編碼“纰謬招致亂碼,但沒有真正想過為何”字符編碼“會招致亂碼。
謎底其實很簡略:“轉換招致亂碼”!
依據這個准繩來斷定,各類情形就很簡略了:

1)數據傳送進程中不會招致亂碼
2)數據存儲不會招致亂碼
3)數據輸出和輸入(包含顯示)能夠招致亂碼
4)數據吸收和發送能夠招致亂碼

更具體的說明:轉換招致亂碼是指原來是A字符集的數據被當做了B字符集停止解析,而不是說准確的A字符集轉換為B字符集。
例如:以下mysql字符處置機制流程圖中,mysql客戶端發送的現實上是2個gbk字符(4字節),但character_set_connection
設置了utf8,因而mysql辦事器將收到的4字節gbk數據依照utf8解析,獲得1個中文字符+1個字節,這時候就發生亂碼了;

假如character_set_connection 設置為gbk,mysql辦事器收到數據後依照gbk解析,獲得兩個准確的中文,然後再轉換為這兩個中文對應的utf8編碼,這就不會發生亂碼。)

【mysql的字符處置機制】

具體的處置機制以下圖:



我們模仿一下一條數據從拔出到讀取的處置流程,看看在全部流程中,字符集是若何展轉騰挪的。
【拔出流程】
1. 客戶端設定了本身的編碼(character_set_client),吸收用戶的輸出;
2. 客戶端將用戶的輸出“轉換”成銜接的編碼(character_set_connection) =====> 第一次轉換
3. 客戶端將轉換後的數據發送給辦事器;                               =====> 傳輸不會招致編碼轉換
4. 辦事器收到客戶真個數據,再斷定數據列的字符集,停止字符轉換       =====> 第二次轉換
5. 辦事器將數據存儲(例如磁盤)                                     =====> 存儲不會招致編碼轉換  

【讀取流程】
略去後面的sql語句處置流程,從數據讀取開端
1. 辦事器從存儲(例如磁盤)讀取數據                                 =====> 存儲不會招致編碼轉換,是以從存儲讀取也不須要
2. 辦事器斷定以後銜接前往成果的字符集(character_set_results),
   將讀取的數據轉換為成果集請求的數據                               =====> 逆向的第一次轉換,對應正向的第二次編碼轉換
3. 辦事器將數據發送給客戶端                                         =====> 傳輸不會招致編碼轉換
4. 客戶端收到辦事器的數據,依據客戶真個字符集(character_set_client)停止編碼轉換          =====> 逆向第二次轉換,對應正向第一次編碼轉換
5. 客戶端顯示數據                                                   =====> 你能看到亂碼的時刻

有了這個流程,我們就很輕易定位亂碼能夠發生的處所,和發生亂碼的字符集設置裝備擺設畢竟是哪一個了。
幻想的情形是全部流程中,一切觸及字符轉換的處所都不須要轉換,如許就不會發生亂碼了。

有了下面的實際剖析後,我們再聯合一個亂碼的抓包實例,加深懂得,個中有一些成績,請年夜家思慮一下,看看能否真的懂得了。

情況:
+--------------------------+-----------------------------------------------------+
| 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                                                |

測試語句是拔出一個中文字符“你”,其utf8編碼為"0xE4 0xBD 0xA0",

1. latin1發送包 


思慮一下1:為何客戶端和銜接都設置了latin1,但終究發送的是准確的utf8編碼呢?

2. latin1吸收包 


思慮一下2:為何吸收到的照樣准確的utf8編碼?

3. latin1不顯示亂碼 


思慮一下3:為何latin1顯示了准確的utf8字符?

4. utf8吸收包 


思慮一下4:為何銜接的字符集和數據庫的字符集設置成一樣了,吸收的數據反而不是utf8了?(請與latin1吸收數據包比較)

5. utf8顯示包


思慮一下5:為何銜接的字符集和數據庫的字符集設置成一樣了,顯示反而亂碼了? 

怎樣樣,下面的思慮題能否都有謎底了,假如沒有,信任上面這幅圖可以或許贊助你:

這個抓包案例的字符變更圖解:


附: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                     |
+--------------------------+-----------------------------------------------------+ 

【修正字符集設置】
辦事器的設置裝備擺設在辦事器樹立的時刻就由DBA設置好了,不推舉後續再改
經由過程SET NAMES utf8敕令同時設置character_set_client/character_set_connection/character_set_results的字符集
建議一切設置裝備擺設都設置成utf8

【成績謎底】

思慮一下1:為何客戶端和銜接都設置了latin1,但終究發送的是准確的utf8編碼呢?
客戶端設置了latin1,而我的語句是從notepad++中寫好的,是utf8格局的;
中文utf8是3個字節,而latin1是依照單個字節解析的,固然停止了轉換,但不會招致二進制內容的變更,但現實上mysql客戶端以為我輸出了3個latin1字符;
假如客戶端設置的編碼是2個字節的gbk,這時候轉換就會產生亂碼,utf8的3個字節會被轉換為1個gbk字符(能夠是亂碼,也能夠不是亂碼)加上一個西歐字符(小於128就是英文,年夜於128就是其它西歐文)

思慮一下2:為何吸收到的照樣准確的utf8編碼?
這是由於mysql辦事器從將數據從“列”的編碼(utf8)轉換為latin1了,而列存儲的數據其實不是真實的utf8的中文“你”對應的"0xe4 0xbd 0xa0",
而是前面抓包看到的“c3a4 c2bd c2a0”(6個字節),mysql辦事器將utf8的c3a4轉換為latin1的0xe4,c2bd轉換為0xbd, c2a0轉換為0xa0

思慮一下3:為何latin1顯示了准確的utf8字符?
由於mysql客戶端收到了mysql辦事器轉換後的"0xe4 0xbd 0xa0",並把這個數據當作latin1的3個字符處置,然後拋給終端(我的是SecureCRT),
SecureCRT又把這三個latin1當作uft8處置,成果中文的“你”就顯示出來了。

思慮一下4:為何銜接的字符集和數據庫的字符集設置成一樣了,吸收的數據反而不是utf8了?(請與latin1吸收數據包比較)
字符集都一樣的情形下,全部流程中不須要停止編碼轉換,直接將存儲的“c3a4 c2bd c2a0”前往給客戶端

思慮一下5:為何銜接的字符集和數據庫的字符集設置成一樣了,顯示反而亂碼了?
參考思慮4,客戶端收到數據後也直接拋給終端顯示,終端以為是兩個utf8字符,而且找到了對應字符並顯示,但我們看不懂,所以曉得是亂碼了,但這兩個字符顯示並沒有錯,假如真正找不到字符,能夠會顯示問號或許字符集劃定的缺省符號。

以上就是關於MySQL亂碼成績年夜聚集,願望可以或許贊助年夜家處理MySQL亂碼成績,感謝年夜家的浏覽。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved