mysql涉及到各種字符集,在此做一個總結。
字符集的設置是通過環境變量來設置的,環境變量和linux中的環境變量是一個意思。mysql的環境變量分為兩種:session和global。session變量是僅在這次會話紅中有效,在mysql中,一次會話可以理解為當前連接(除非reload,否則,一次會話就只有一次連接)。global環境變量則是確定了下一個新建立的session的變量值。使用show variables可以查看session值,如果要查看global的環境變量,則用show golbal variables語句。設置session環境變量用set variablename=value,設置global環境變量用set global variablename=value。
環境變量可以在服務啟動后用set來設置,有些(主要是和數據庫服務器有關的)也可以在啟動服務時用命令行參數指定,還可以在配置文件中設置(my.cnf)。
mysql提供了四個等級的默認字符集以及比較規則,分別是服務器、數據庫、表、列級別的。文檔原話是:There are default settings for character sets and collations at four levels: server, database, table, and column. The description in the following sections may appear complex, but it has been found in practice that multiple-level defaulting leads to natural and obvious results.
一個字符集(character set)對應了一個默認的字符排序碼規則(collation),當改變了一個等級的默認編碼集時,與它同等級的默認字符排序規則也會變成該字符集對應的字符排序規則。
除了有這四個等級的默認字符編碼和排序規則,還可以指定具體某一段字符的編碼以及他的排序規則,指定字符編碼是直接在他前面加上_utf8就可以了,指定排序規則在后面加上collate<排序規則>,如下這樣: SELECT _utf8'abc' COLLATE utf8_danish_ci; 注意,如果有轉義字符,那么轉義字符是不會收字符串指定編碼集影像的,而是和character_set_connection一致,如下:
1 mysql> SET NAMES latin1; 2 mysql> SELECT HEX('à\n'), HEX(_sjis'à\n');
返回的結果中\n仍然是換行符,因為\用的是latin1的字符集,在latin1中,它是換行符,而_sijis字符集中,\不是轉移字符,而是6E
。
結果:
+------------+-----------------+ | HEX('à\n') | HEX(_sjis'à\n') | +------------+-----------------+ | E00A | E00A | +------------+-----------------+
如果要查看所有的字符集,用show character set語句,查看所有的collation,用show collation語句。
字符集的設定不僅影響着存儲,還會影響客戶端和數據庫服務器的通信,關於數據編碼,mqsql中涉及到下面幾個問題:
1、客戶端發過來的數據使用什么字符集編碼的?
2、接收到數據之后,應該用什么編碼格式編碼之后再將數據插入到mysql server中?
3、執行查詢之后,查詢出來的結果應該用什么編碼集編碼之后再返回?
4、數據庫的各種表的數據,應該用什么字符集編碼,以及它們用什么排序?
5.查詢語句的字符串比較時,應該在哪一個標准里面來比較,比如:'Mueller' = 'Müller'是為真還是假?
6.數據庫的各種元數據,包括表名、數據庫名、密碼、用戶名、以及comment等,用什么字符集表示?
針對這四個問題,mysql就提供了不同的環境變量來進行跟蹤,這些變量為:
變量名 |
含義 |
character_set_server |
默認的內部操作字符集 |
character_set_client |
客戶端來源數據使用的字符集,也就是客戶端發過來的查詢語句使用的什么字符集 |
character_set_connection |
MySQL接受到用戶查詢后,按照character_set_client將其轉化為character_set_connection設定的字符集。 |
character_set_results |
查詢結果編碼的字符集 |
character_set_database |
當前選中數據庫的默認字符集 |
character_set_system |
系統元數據(字段名等)字符集 |
collation_connection |
執行字符比較時采用的編碼規則 |
在mysql中,可以為數據庫指定默認的字符編碼,成為該數據庫中每個新建表的默認字符編碼集,但是對於已經建立的表則不受影響。在新建一個表時,也可以使用DEFUALT CHARACTER SET=xxx來指定表的字符編碼。
在數據庫的查詢(select update insert)操作中,涉及到的字符編碼有character_set_client, character_set_connnection, character_set_result三個變量,這是三個變量是需要建立連接之后進行設置的.
1、針對第一個問題,使用character_set_client環境變量來回答:
character_set_client ,這是用戶告訴服務器,客戶端發過來的SQL語句是用的什么字符集,要和客戶端發出去的字節流采用的編碼集一致,如果是shell,那么就是和shell的編碼集一致,中文windows的cmd就是gbk。但是對於使用_utf8'xxx'標記的字符,則用標記的字符集解碼。
2、針對第二個問題,使用character_set_connetion環境變量來回答:
character_set_connection ,MySQL server 接收到用戶查詢后,按照character_set_client將其轉化為character_set_connection設定的字符集,一般就是所操作的表對應的編碼集。
3、針對第三個問題,使用character_set_result環境變量來回答:
character_set_results , MySQL將存儲的數據轉換成character_set_results中設定的字符集發送給用戶,客戶端獲取到的結果就是以這種形式編碼的。
4.針對第四個問題,使用上面提到的四個等級的默認字符集以及排序規則,即character_set_server、character_set_database以及建立表時的DEFAULT CHARACTER SET=xxx和指定字段時的DEFAULT CHARACTER SET=xxx來回答:
character_set_server決定了服務器的默認編碼,character_set_database決定了新建數據庫的默認字符集,而數據庫的字符集又決定了新建表的默認字符集,而表的字符集又決定了字段的默認字符集,如果沒有通過DEFAULT CHARACTER SET=xxx來改變表的字符集,則新表就使用character_set_database指定的字符集。
5.針對第五個問題,使用collation_connection來回答:
collation_connection變量制定了比較的規則。collation_connection的值得形式如下:字符集_語言_ci(大小不寫敏感) 或字符集_語言_cs(大小寫敏感),像中文這樣的,沒有大小寫,所以只能是ci,比如set collatioin_connection=gbk_chinese_ci。就是設置成中文字典的排序規則。除了按具體語言排序,還可以按照二進制的位置排序,比如utf8_bin。
character_set_connection和collatioin_connection是一體的,設置了character_set_connection之后,collation_connection會跟着變成對應的默認排序規則,反之亦然。如果要顯示的設置排序規則,可以用 SET NAMES 'charset_name' COLLATE 'collation_name' 。
但是如果查詢語句的字符串和表的字段比較,則collation_connection不適用,因為表的字段有它自己的字符排序規則,而它自己的排序規則優先級高於collation_connection。
6.針對第六個問題,使用character_set_system來回答:
character_set_system表示元數據的字符集,默認就是utf8,而且不要去更改它,否則,因為類似於用戶名密碼這種東西,可能用各種奇葩的字符去表示,只有utf8能夠容納它們。如果變成了別的字符集,那么用戶名和密碼就不能用你想要的字符去表示了。需要注意的是,這個character_set_system也好,character_set_dababase、character_set_server也好,都指標是在數據庫內部的保存格式,而不是返回到客戶端的編碼格式,返回到客戶端的結果都會轉化為character_set_results指定的字符集之后再返回,官方文檔原話是“Storage of metadata using Unicode does not mean that the server returns headers of columns and the results of DESCRIBE
functions in the character_set_system
character set by default. When you use SELECT column1 FROM t
, the name column1
itself is returned from the server to the client in the character set determined by the value of the character_set_results
system variable, which has a default value of latin1
.”。
另外,如果要臨時設置返回值的編碼,可以用set names charset_name'來臨時改變character_set_results以及其他相關變量的值為charset_name。set names 'charset_name'等價於下面三條語句的結合:
1 SET character_set_client = charset_name; 2 SET character_set_results = charset_name; 3 SET character_set_connection = charset_name;
SET CHARACTER SET
和 SET NAMES
很像,但是是把 character_set_connection
和 collation_connection
分別設置為 character_set_database
和 collation_database
一樣,SET CHARACTER SET
等同於以下三條語句的結合。charset_name
1 SET character_set_client = charset_name; 2 SET character_set_results = charset_name; 3 SET collation_connection = @@collation_database;
所以,set character set 'charset_name'要更常用。
順便提一句,mysql的錯誤日志意識utf8格式產生的,但是如果把它輸出到客戶端,它就會轉場character_set_results的編碼格式再傳到客戶端(所有傳到客戶端的東西都會轉碼成character_set_results的)。
還可以加入啟動參數skip-character-set-client-handshake來使客戶端的編碼和數據庫保持一致。
通常,客戶端的字符集可以通過操作系統來獲取,從而使得字符集的分配和客戶端一致。
參考:1、Connection Character Sets and Collations
3、What are character sets and collations
5、Mysql中的排序規則utf8_unicode_ci、utf8_general_ci的區別總結