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亂碼成績,感謝年夜家的浏覽。