一、基本概念(這裡引用http://www.laruence.com/2008/01/05/12.html) 1、 給定一系列字元,對每個字元賦予一個數值,用數值來代表對應的字元,這一數值就是字元的編碼(Encoding)。例如,我們給字元’A'賦予數值0,給字元’B'賦予數值1,則0就是字元’A' ...
一、基本概念(這裡引用http://www.laruence.com/2008/01/05/12.html)
1、 給定一系列字元,對每個字元賦予一個數值,用數值來代表對應的字元,這一數值就是字元的編碼(Encoding)。例如,我們給字元’A'賦予數值0,給字元’B'賦予數值1,則0就是字元’A'的編碼;
2、 給定一系列字元並賦予對應的編碼後,所有這些字元和編碼對組成的集合就是字元集(Character Set)。例如,給定字元列表為{‘A’,'B’}時,{‘A’=>0, ‘B’=>1}就是一個字元集;
3、字元序(Collation)是指在同一字元集內字元之間的比較規則;
4、確定字元序後,才能在一個字元集上定義什麼是等價的字元,以及字元之間的大小關係;
5、每個字元序唯一對應一種字元集,但一個字元集可以對應多種字元序,其中有一個是預設字元序(Default Collation);
6、MySQL中的字元序名稱遵從命名慣例:以字元序對應的字元集名稱開頭;以_ci(表示大小寫不敏感)、_cs(表示大小寫敏感)或_bin(表示按編碼值比較)結尾。例如:在字元序“utf8_general_ci”下,字元“a”和“A”是等價的;
二、名詞解釋
1、character_set_client:客戶端數據解析、編碼的字元集。
2、character_set_connection:連接層字元集。
3、character_set_server:伺服器內部操作字元集。
4、character_set_results:查詢結果字元集。
5、character_set_database:當前資料庫的字元集。
6、character_set_system:系統源數據(欄位名等)字元集。
註:
1、還有以collation_開頭的同上面對應的變數,用來描述字元序。
2、服務端編碼、解析時,是按照前一環節的編碼進行解析的,按照各自的字元集進行編碼的。
3、character_set_server是mysql資料庫記憶體的操作字元集。如果創建資料庫時,沒有指定資料庫的字元集,則使用character_set_server的字元集作為預設字元集;如果創建表時,沒有指定表的字元集,則使用character_set_database的字元集作為預設字元集;如果在創建欄位時,沒有指定欄位的字元集,則使用表的字元集作為預設字元集。
4、set names gbk;等同於同時設置character_set_client,character_set_connection,character_set_results這三個字元集。
三、數據傳輸過程中字元集編碼、解析
1.客戶端以及編碼
我們使用jdbc操作數據的程式、navicate操作工具、操作系統操作資料庫這些都認為是客戶端。客戶端navicate的編碼為utf8,windows預設的編碼為gbk。一般情況下,utf8編碼的中文占三個位元組,gbk占用兩個位元組(一個位元組是8位二進位,也就是兩個十六進位)。
Navicate操作(utf8) mysql> show variables like '%char%'; +--------------------------+----------------------------+ | Variable_name | Value | +--------------------------+----------------------------+ | character_set_client | utf8 | | character_set_connection | utf8 | | character_set_database | utf8 | | character_set_filesystem | binary | | character_set_results | utf8 | | character_set_server | utf8 | | character_set_system | utf8 | | character_sets_dir | /usr/share/mysql/charsets/ | +--------------------------+----------------------------+ 8 rows in set mysql> select hex('我很帥'); +--------------------+ | hex('我很帥') | +--------------------+ | E68891E5BE88E5B885 | +--------------------+ 1 row in set
Windows上操作(gbk) mysql> show variables like '%char%'; +--------------------------+----------------------------+ | Variable_name | Value | +--------------------------+----------------------------+ | character_set_client | gbk | | character_set_connection | gbk | | character_set_database | utf8 | | character_set_filesystem | binary | | character_set_results | gbk | | character_set_server | utf8 | | character_set_system | utf8 | | character_sets_dir | /usr/share/mysql/charsets/ | +--------------------------+----------------------------+ 8 rows in set mysql> select hex('我很帥'); +--------------------+ | hex('我很帥') | +--------------------+ | CED2BADCCAA7 | +--------------------+ 1 row in set
2.解析過程
a.sql語句通過客戶端編碼發送到mysql伺服器上;
b.character_set_client對接收到的數據進行解碼,這裡解碼按照character_set_client編碼進行解碼,最後按照自身字元集進行編碼。
c.character_set_connection收到來自client的編碼,這裡進行字元集轉換。註意這裡s.decode(character_set_client).encode(character_set_connection)。
d.character_set_server這裡是伺服器內部使用的字元集,如果單獨給欄位添加字元集,這裡取的是欄位字元集。這裡收到connection的編碼,進行字元集轉換。e.decode(character_set_connection).encode(character_set_server)。
3.查詢過程
a.mysql伺服器轉換為character_set_results發送到客戶端,其實這裡你只要知道最後從伺服器出來的時候是按照character_set_results編碼的。
b.發送到客戶端之後,按照客戶端編碼進行解碼。所以如果character_set_results和客戶端編碼不一致,會導致查詢亂碼。
ps:這裡我創建一個gbk表,裡面插入有數據(自己構造,帶有中文)。
Navicate操作(utf8) mysql> select @@character_set_results; +-------------------------+ | @@character_set_results | +-------------------------+ | utf8 | +-------------------------+ 1 row in set mysql> select name_man from wsyy_marry where id = 1; +----------+ | name_man | +----------+ | 赫立廣 | +----------+ 1 row in set mysql> set @@session.character_set_results = 28; Query OK, 0 rows affected mysql> select @@character_set_results; +-------------------------+ | @@character_set_results | +-------------------------+ | gbk | +-------------------------+ 1 row in set mysql> select name_man from wsyy_marry where id = 1; +----------+ | name_man | +----------+ | ������ | +----------+ 1 row in set
Windows操作(gbk) mysql> select @@character_set_results; +-------------------------+ | @@character_set_results | +-------------------------+ | gbk | +-------------------------+ 1 row in set mysql> select name_man from wsyy_marry where id = 1; +----------+ | name_man | +----------+ | 赫立廣 | +----------+ 1 row in set mysql> set @@session.character_set_results = 33; Query OK, 0 rows affected mysql> select @@character_set_results; +-------------------------+ | @@character_set_results | +-------------------------+ | utf8 | +-------------------------+ 1 row in set mysql> select name_man from test.wsyy_marry where id = 1; +----------+ | name_man | +----------+ | 璧珛騫� | +----------+ 1 row in set
四、總結
1、字元集設置33,代表utf8;28代表gbk字元集設置33;
2、字元集出現亂碼的地方最大可能在兩個地方,character_set_client和character_set_results。如果這兩個地方的編碼個客戶端編碼不一致會亂碼。告訴你,有可能存都存不進去。
3、後面也有可能出現編碼問題,如果中文字元串,latin1解碼不了中文,則會出現亂碼。也就是說進行編碼轉換的時候可能出現不相容的情況,latin1編碼的都能被utf8相容,反之就可能出現”??”這樣的情況。
4、看下來之後老老實實不要亂設置character_set_client這些值。如果能保持所有的都是utf8,那肯定沒問題。
五、疑問
客戶端編碼 |
client |
connection |
server |
結果 |
utf8 |
gbk |
gbk |
gbk/utf8 |
插入失敗 |
utf8 |
gbk |
utf8 |
gbk/utf8 |
插入亂碼 |
utf8 |
utf8 |
gbk |
gbk/utf8 |
正常插入 |
utf8 |
urf8 |
utf8 |
gbk/utf8 |
正常插入 |
我做瞭如下統計,客戶端編碼和character_set_client編碼不一致有可能出現插入亂碼,也有可能出現數據插都插不進去。我也不知道為啥會不能插入資料庫。下麵這兩種情況很大都是可能是亂碼導致的報錯。
1、Incorrect string value: '\xB6' for column 'NAME_MAN' at row 1。
2、SQLException errorcom.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column 'NAME_MAN' at row 1。
如果對這裡面介紹有異議或者能有更全面的理解可以在下麵留言,大家共同學習。
六、參考資料
1.http://www.jianshu.com/p/96ee5b2adef3
2.http://blog.csdn.net/kxcfzyk/article/details/37723367
3.http://www.laruence.com/2008/01/05/12.html