MySQL 字元轉化以及亂碼原因
1MySQL 中存入數據時發生的編碼轉換過程:
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 需要經過三次編碼,兩次編碼轉化。
2MySQL 中取出數據時發生的編碼轉換過程:
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) 之間的轉換是為了在從數據文件讀入數據後,在存儲引擎內部進行字元級別的操作。
3經過以上分析,應該很快發現導致亂碼出現的原因是有以下幾種:
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 的三個字符集完全一致就可以保證一定不會有亂碼出現了。
轉自:MySQL 字元轉化以及亂碼原因
推薦閱讀:
※mysql注入篇
※使用explain語句查詢索引查詢索引是否在使用
※提高MySQL性能的7個技巧
※MySQL及MySQL-workbench安裝
※專精 Oracle 還是 MySQL?