在閱讀代碼的時候,經(jīng)衬蚱叮看到遇到這樣一句
$this->pdo->exec("SET NAMES '" . $config["charset"] . "'");
心生疑惑 ,“為什么在數(shù)據(jù)讀寫之前踏揣,要寫這樣一句”庆亡。
求助了一下搜索引擎,原來是為了避免亂碼的出現(xiàn)捞稿。下面就來說說 MySQL 為什么會出現(xiàn)亂碼以及解決亂碼的方法
先明確幾個概念
什么是字符集(character set)呢又谋?mysql 的文檔給了一個很容易理解的例子
假設(shè)有個包含4個字符的字母表 A,B,a,b。
給每個字母編一個號娱局,A=0彰亥,B=1,a=2衰齐,b=3
這里的 A 就是 符號(symbol)任斋,0 就是 A 的編碼(encoding)
符號和符號對應(yīng)的編碼就組成了一個字符集
那么什么又是 collation 呢?
簡單來說耻涛,它就是 order by
時废酷,用來排序的規(guī)則瘟檩。
字符集 utf8 下常用的 collation 有 utf8_general_ci、utf8__bin澈蟆。
ci 指的就是case incensitive
墨辛,大小寫不敏感。比較時趴俘,a 和 A 是相同的
為什么會出現(xiàn)亂碼睹簇?
MySQL 的中的字符集變量
- character_set_server:默認(rèn)的內(nèi)部操作字符集
- character_set_client:客戶端來源數(shù)據(jù)使用的字符集
- character_set_connection:連接層字符集
- character_set_results:查詢結(jié)果字符集
- character_set_database:當(dāng)前選中數(shù)據(jù)庫的默認(rèn)字符集
- character_set_system:系統(tǒng)元數(shù)據(jù)(字段名等)字符集
- 還有以collation_開頭的同上面對應(yīng)的變量,用來描述字符序
客戶端要讀寫數(shù)據(jù)庫時寥闪,需要建立一條數(shù)據(jù)庫連接 connection带膀。
數(shù)據(jù)從客戶端到服務(wù)端
數(shù)據(jù)在 connection 上,傳輸?shù)倪^程中需要經(jīng)過編碼轉(zhuǎn)換
character_set_client ---> character_set_connection ---> column_character_set
|--> table_character_set
|--> database_character_set
|--> character_set_server
|--> character_set_result
- 服務(wù)端收到客戶端的數(shù)據(jù)時橙垢,認(rèn)為客戶端的數(shù)據(jù)編碼為
character_ser_client
- 隨后將從客戶端接收到的數(shù)據(jù),轉(zhuǎn)換為
character_set_connection
編碼 - 在需要進(jìn)行數(shù)據(jù)庫內(nèi)部操作(寫到表等)的時候伦糯,將
character_set_connection
編碼轉(zhuǎn)換字段柜某、表、數(shù)據(jù)庫敛纲、服務(wù)器對應(yīng)的編碼類型 - 若以上值不存在喂击,則轉(zhuǎn)化為
character_set_results
數(shù)據(jù)從服務(wù)端到客戶端
character_set_result ---> character_set_connection ---> character_set_client
為數(shù)據(jù)從客戶端到服務(wù)端相反過程
可以看到轉(zhuǎn)換過程中,有幾個地方可能會產(chǎn)生亂碼
- character_set_client 和真實的客戶端編碼不同
- client->server, server->client 兩個過程中使用的編碼不一致
- 編碼轉(zhuǎn)換不可逆淤翔,導(dǎo)致信息丟失
這里有解決辦法
在進(jìn)行連接后翰绊,就進(jìn)行設(shè)置編碼,之后的讀寫都不再改變
SET NAMES character_name
相當(dāng)于
SET character_set_client = charset_name;
SET character_set_results = charset_name;
SET character_set_connection = charset_name;
這樣可以解決上述的前連個問題
但是第三個問題旁壮,要看數(shù)轉(zhuǎn)換的數(shù)據(jù)是否存在兩個字符集之間的轉(zhuǎn)換不可逆的字符
如有錯誤监嗜,還望指正!