標籤:character 伺服器 資料庫 mysql 字串
什麼是字元集?
字元集是一套符號和編碼的規則,可以想象為二進位位和符號的轉換表。
MySQL支援的字元集
MySQL資料庫可以支援多種字元集。
MySQL字元集包括字元集(character set)和校對規則(collation)兩個概念。字元集是用來定義MySQL儲存字串的方式,校對規則則是用來定義了比較字串的方式。字元集和校對規則是一對多的關係。
每個字元集至少對應一個校對規則。
# 查看支援的字元集mysql> SHOW CHARACTER SET;# 查看支援的校對規則mysql> SHOW COLLATION;
MySQL字元集設定非常靈活,分別可以在伺服器級、資料庫級、表級、欄位級設定。
資料庫物件的字元集的指定有如下繼承關係:
Server -> Database -> Table -> Column
也就是說,如果某一級沒有顯示指定字元集,那麼將繼承上一級的字元集。
# 查看伺服器字元集相關的系統變數mysql> SHOW VARIABLES LIKE ‘%char%‘;
650) this.width=650;" src="http://s3.51cto.com/wyfs02/M00/57/0F/wKioL1SQVebgKuIHAANaVutXzkI147.jpg" title="34.png" alt="wKioL1SQVebgKuIHAANaVutXzkI147.jpg" />
亂碼問題?
MySQL處理串連時,外部串連發送過來的SQL請求會根據以下順序進行轉換:
character_set_client //客戶串連所採用的字元集
|
character_set_connection //MySQL串連字元集
|
character_set_database //資料庫所採用的字元集(表,列)
|
character_set_results //返回的結果所採用的字元集
我們告訴伺服器,我發送給你的資料是什麼編碼? character_set_client
如果發現和連接器指定的編碼不一致,要轉換為什麼編碼? character_set_connection
查詢的結果用什麼編碼? character_set_results
如果以上三者都為字元集N,可簡寫為: set names N;
下面通過執行個體來示範為什麼會亂碼?
# 建立一個表mysql> CREATE TABLE person ( -> id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, -> name VARCHAR(30) -> ) DEFAULT CHARSET utf8;# 然後執行下面3條命令, 可以簡寫為 set names utf8;set character_set_client=utf8;set character_set_connection=utf8;set_character_set_results=utf8;# 查看當前字元集設定mysql> show variables like ‘%char%‘;+--------------------------+----------------------------+| Variable_name | Value |+--------------------------+----------------------------+| character_set_client | utf8 || character_set_connection | utf8 || character_set_database | latin1 || character_set_filesystem | binary || character_set_results | utf8 || character_set_server | latin1 || character_set_system | utf8 || character_sets_dir | /usr/share/mysql/charsets/ |+--------------------------+----------------------------+# 然後插入一條資料mysql> INSERT INTO person(name) VALUES(‘中文‘);# 查詢mysql> SELECT * FROM person;+----+--------+| id | name |+----+--------+| 1 | 中文 |+----+--------+# 顯示結果是正常的。# 好,接下來,我們改變character_set_results 為 gbkmysql> set character_set_results=gbk;Query OK, 0 rows affected (0.04 sec)mysql> SELECT * FROM person;+----+------+| id | name |+----+------+| 1 | |+----+------+
產生亂碼的根本原因就是:
各字元集系統變數不一致,導致進行字元集轉換。
比如說:客戶機沒有正確地設定client字元集,導致原先的SQL語句被轉換成connection所指字元集,而這種轉換,可能是會丟失資訊的,如果client是utf8格式,那麼如果轉換成gb2312格式,這其中必定會丟失資訊,反之則不會丟失。一定要保證connection的字元集大於client字元集才能保證轉換不丟失資訊。同理,connection與results也是這樣。就像程式設計語言中的資料類型相互轉換時一樣,比如把double類型強制轉換成int類型,就會造成精度的丟失一樣。
我們來仔細說明一下轉換的過程:
向預設字元集為utf8的資料表插入utf8編碼的資料前沒有設定串連字元集,查詢時設定串連字元集為utf8
– 插入時根據MySQL伺服器的預設設定,character_set_client、character_set_connection和character_set_results均為latin1;
– 插入操作的資料將經過latin1=>latin1=>utf8的字元集轉換過程,這一過程中每個插入的漢字都會從原始的3個位元組變成6個位元組儲存;
– 查詢時的結果將經過utf8=>utf8的字元集轉換過程,將儲存的6個位元組原封不動返回,產生亂碼。
向預設字元集為latin1的資料表插入utf8編碼的資料前設定了串連字元集為utf8
– 插入時根據串連字元集設定,character_set_client、character_set_connection和character_set_results均為utf8;
--插入資料將經過utf8=>utf8=>latin1的字元集轉換,若未經處理資料中含有\u0000~\u00ff範圍以外的Unicode字元,會因為無法在latin1字元集中表示而被轉換為“?”(0×3F)符號,以後查詢時不管串連字元集設定如何都無法恢複其內容了。
綜上,終極解決方案如下:
1.首先要明確你的用戶端時候何種編碼格式,這是最重要的(IE6一般用utf8,命令列一般是gbk,一般程式是gb2312)
2.確保你的資料庫使用utf8格式,很簡單,所有編碼通吃。
3.一定要保證connection字元集大於等於client字元集,不然就會資訊丟失,比如: latin1 < gb2312 < gbk < utf8,若設定set character_set_client = gb2312,那麼至少connection的字元集要大於等於gb2312,否則就會丟失資訊
4.以上三步做正確的話,那麼所有中文都被正確地轉換成utf8格式儲存進了資料庫,為了適應不同的瀏覽器,不同的用戶端,你可以修改character_set_results來以不同的編碼顯示中文字型,由於utf8是大方向,因此web應用是我還是傾向於使用utf8格式顯示中文的。
總結
根據上面的分析和建議,我們解決我們遇到問題應該使用什麼方法大家心裡應該比較清楚了。對,就是在建立database的時候指定字元集,不要去通過修改預設配置來達到目的,當然你也可以採用指定表的字元集的形式,但很容易出現遺漏,特別是在很多人都參與設計的時候,更容易紕漏。
http://www.cnblogs.com/zzwlovegfj/archive/2012/06/25/2560649.html
http://www.cnblogs.com/discuss/articles/1862248.html
本文出自 “Share your knowledge” 部落格,請務必保留此出處http://skypegnu1.blog.51cto.com/8991766/1591215
MySQL字元集亂碼