一、基本概念(這裡引用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
轉載于:https://www.cnblogs.com/jave1ove/p/7454966.html