mysql字元轉化以及亂碼原因

dbasdk發表於2017-04-19
mysql中存入資料時發生的編碼轉換過程:
1、在終端(Terminal,可以是bash視窗,也可以是客戶端工具如navicat)中輸入,輸入的內容由Terminal根據其自己的字元進行編碼。
2、經Terminal編碼後的二進位制流被傳輸到mysql server。mysql server(mysql engine)根據引數character_set_client的字元設定來對該二進位制流進行解碼。
3、解碼之後,mysql server再次根據目的表,即table的字符集來判斷是否需要字元編碼轉換。如果character_set_client的字元設定和table定義時的character設定一致,則無需字元編碼轉換。否則進行轉換,然後將轉換後的二進位制流存放到資料檔案(file)中去。
總結:client ------> server(engine) -----> file     需要經過三次編碼,兩次編碼轉化。

mysql中取出資料時發生的編碼轉換過程:
1、從資料檔案(file)中讀出二進位制資料流,將該資料流根據table定義時的character設定來進行解碼。
2、在用table character對二級制資料流進行解碼之後,在mysql engine(mysql server)中,需要根據引數character_set_client的字符集設定對解碼後的資料庫流再一次進行編碼,將編碼之後的二級制資料庫流傳輸到client端。
3、client端,即終端(Terminal)根據其自己的字符集編碼來展示查詢結果。
總結:  file ------> server(engine) -----> client  需要經過三次編碼,兩次編碼轉化。

可能會有些疑問,在上面的分析中,資料都是以二進位制流的方式在各個節點之間流動的。那麼為什麼需要編碼轉化了?
1、client 和 server(engine) 之間的轉換,或者說編解碼是為了對傳進來的二進位制流做語法和詞法解析,否則你不會知道傳進來的是insert還是update。
2、file 和 server(engine) 之間的轉換是為了在從資料檔案讀入資料後,在儲存引擎內部進行字元級別的操作。

經過以上分析,應該很快發現導致亂碼出現的原因是有以下幾種:
1、資料在存入的時候和取出的時候,編碼不一致。比如存入時用的utf8,取出時用的GBK。
2、編碼轉換不是無損編碼轉換導致亂碼出現。比如clien是utf8,mysql server中的character_set_client設定為gbk,表結構的字符集設定為utf8。這裡會有兩次編碼轉化,client到server時,utf8要轉為gbk,然後server到file時,gbk要轉為utf8。由於gbk到utf8是有損編碼轉化,導致了亂碼出現。

無損編碼轉換:假設我們要把用編碼A表示的字元X,轉化為編碼B的表示形式,而編碼B的字形集中並沒有X這個字元,那麼此時我們就稱這個轉換是有損的。
但不是任何兩種字符集編碼之間的轉換都是有損,轉換是否有損取決於以下幾點:
------被轉換的字元是否同時在兩個字符集中
------標字符集是否能夠對不支援字元,保留其原有表達形式。(比如latin1在遇到自己無法表示的字元時,會保留原字符集的編碼資料,並跳過忽略該字元進而處理後面的資料。)

因此只要客戶端,MySQL Server的character-set-client,table charset的三個字符集完全一致就可以保證一定不會有亂碼出現了。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29734436/viewspace-2137629/,如需轉載,請註明出處,否則將追究法律責任。

相關文章