字符集&字符編碼方式mysql
字符集(Character set)是多個字符的集合,字符集種類較多,每一個字符集包含的字符個數不一樣,這裏的字符能夠是英文字符,漢字字符,或者其餘國家語言字符。
常見字符集包括:ASCII字符集、LATIN1字符集、GB2312字符集、GBK字符集、GB18030字符集、Unicode字符集等。字符編碼方式是用一個或多個字節表示字符集中的一個字符。每種字符集都有本身特有的編碼方式,所以同一個字符,在不一樣字符集的編碼方式下,會產生不一樣的二進制。ASCII是基於羅馬字母表的一套字符集,它採用1個字節的低7位表示字符,高位始終爲0。LATIN1字符集相對於ASCII字符集作了擴展,仍然使用一個字節表示字符,但啓用了高位,擴展了字符集的表示範圍。GB23十二、GBK、GB18030字符集是支持中文的字符集,字符集範圍GB2312<GBK< GB18030。GBK字符集的字符有一字節編碼和兩字節編碼方式。對於00-7F的字符與ASCII保持一致,漢字採用2個字節表示。第一字節範圍是81-FE,避免與00-7F衝突。Unicode字符集是計算機科學領域裏的一項業界標準,支持了全部國家的文字字符。Unicode字符集有好幾種編碼方式,好比常見的utf-8,utf-16,utf-32等。Utf8採用1-4個字節表示字符,utf-16採用固定的2個字節,utf-32則採用4個字節存儲。算法
mysql與字符集sql
只要涉及到文字的地方,就會存在字符集和編碼方式。對於mysql數據庫系統而言,用戶從mysql client端敲入一條sql語句,經過TCP/IP傳遞給mysql server進程,到最終存入server端的文件,每一個環節都涉及到字符存儲。涉及到字符存儲的地方,就涉及到字符集編碼,經過mysql提供的系統變量就可見一斑。mysql字符集設置系統變量以及含義以下表:數據庫
變量名編碼 |
含義spa |
character_set_server命令行 |
默認的內部操做字符集code |
character_set_clientserver |
客戶端來源數據使用的字符集 |
character_set_connection |
鏈接層字符集 |
character_set_results |
查詢結果字符集 |
character_set_database |
當前選中數據庫的默認字符集 |
character_set_system |
系統元數據(字段名等)字符集 |
以上這些參數如何起做用
1.庫、表、列字符集的由來
(1).建庫時,若未明確指定字符集,則採用character_set_server指定的字符集。
(2).建表時,若未明確指定字符集,則採用當前庫所採用的字符集。
(3).新增,修改表字段時,若未明確指定字符集,則採用當前表所採用的字符集。
2.更新、查詢涉及到得字符集變量
用戶在更新(插入,刪除,修改),查詢數據庫時,最常使用的字符集變量主要包含character_set_client,character_set_connection,character_set_result。
更新流程字符集轉換過程:character_set_client-》character_set_connection-》表字符集。
查詢流程字符集轉換過程:表字符集-》character_set_result
PS:我的認爲character_set_connection鏈接字符集設置有點冗餘,由於最終都是要轉換到表字符集的。
3.character_set_database
這個參數是當前默認數據庫的字符集,好比執行use xxx後,當前數據庫變爲xxx,若xxx的字符集爲utf8,那麼這個變量值就變爲utf8。所以這個參數是供系統設置,無需人工設置。
mysql字符編碼轉換流程
若是以上各個系統變量的設置不一致,好比character_set_client爲UTF8,而character_set_database爲GBK,則會出現須要進行編碼轉換的狀況。那麼字符集轉換的原理是什麼?假設GBK字符集的字符串「小明」,須要轉爲UTF8字符集存儲,實際就是對於「小明」字符串中的每一個漢字去UTF8編碼表裏面查詢對應的二進制,而後存儲,僅此而已,編碼轉換並不涉及到複雜的算法。mysql字符集轉換主要涉及到幾個步驟:
1) 將數據從character_set_client設置轉換爲character_set_connection設置;
2) 將character_set_connection設置轉爲表字段的字符集設置;
3) 將操做結果從表字段字符集轉爲character_set_results設置。
下面我經過一個經常使用的場景來描述字符集轉換的流程。用戶經過mysql命令行(若是是遠程鏈接:SecureCRT),敲入命令「insert into T values(1,’小明’)」,字符串’小明’在流轉過程當中二進制存儲內容。
a) 用戶採用的客戶端爲utf8字符集,character_set_client=gbk,character_set_connection=gbk, 表T採用gbk字符集。
因爲character_set_client、character_set_connection和表字符集均爲GBK,不涉及編碼轉換。所以,表雖然爲字符集雖然爲GBK,但「小明」的編碼並不是爲GBK編碼的二進制流,而是UTF8的二進制流,兩個漢字佔用了6個字節,而讀取則是一個逆向的過程,不涉及到編碼轉換,查詢依然能正確返回「小明」。
b) 在a)的狀況下,改變character_set_client的設置爲utf8,查詢插入的值。
能夠看到返回的值是「灝忔槑」, 這是因爲表的字符集是GBK,而客戶端請求是UTF8,那麼server將二進制流E5B08FE6988E對應的GBK漢字「灝忔槑」轉爲UTF8漢字對應的二進制流E7818FE5BF94E6A791,所以查詢結果在SecureCRT就顯示爲「灝忔槑」,即一般咱們所謂的亂碼。
c) 在b)的狀況下,設置SecureCRT的字符集爲GBK,看看SecureCRT字符集設置對結果影響
能夠看到返回的是另一組字符「鐏忓繑妲�」,整個流轉過程與b)同樣,只是在第一步發生了字節流轉換,設置SecureCRT字符集編碼,只是改變了顯示方式。
字符集相關的SQL語句
1) 查看字符集編碼設置
SHOW VARIABLES LIKE ‘%CHARACTER%’
2) 設置字符集編碼
SET NAMES xxx;
這個語句至關於設置了client的字符集,主要包含3個系統變量,character_set_client,character_set_connection和character_set_results。
3) 修改數據庫字符集
ALTER DATABASE DATABASENAME CHARACTER SET XXX;
這個語句只修改庫的字符集,影響後續建立的表的默認定義;對於已建立的表的字符集不受影響。
4) 修改表的字符集
ALTER TABLE TABLENAME CHARACTER SET XXX;
這個語句只修改表的字符集,影響後續該表新增列的默認定義,已有列的字符集不受影響。
ALTER TABLE TABLENAME CONVERT TO CHARACTER SET XXX;
這個語句同時修改表字符集和已有列字符集,並將已有數據進行字符集編碼轉換。
5) 修改列字符集
ALTER TABLE `TABLE_NAME` MODIFY COLUMN `COLUMN_NAME` CHARACTER SET xxx
6) 查詢字符的二進制編碼
SELECT HEX(COL_NAME) FROM TABLE_NAME; SELECT LENGTH(COL_NAME) FROM TABLE_NAME;
對於GBK的表,若是查出來一個字符佔用了3個字節,好比圖1這種狀況,則確定是字符集在某個環節設置統一,圖1就是由於客戶端是UTF8,而mysqlclient和database都是GBK形成的。
mysql默認的字符集latin1
mysql 4.x版本以前默認採用的是latin1字符集(又稱ISO-8859-1),latin1字符集編碼方式採用單字節編碼。拋一個問題,latin1字符集的表,用戶寫入和讀取漢字是否有問題?答案是隻要合理設置,沒有問題。假設SecureCRT爲UTF8,character_set_client和表字符集均設置爲latin1,參考第3節的分析,那麼用戶讀取和寫入數據的過程當中,並不涉及字符集編碼轉換的問題,將UTF8的漢字字符轉爲二進制流寫入database,提取出來後,secureCRT再將對應的二進制解碼爲對應的漢字,因此不影響用戶的使用。可是,若character_set_client,character_set_connection,與表字符集設置等不統一,就可能出現亂碼的狀況。