MySQL 配置文件中忘配置default-character-set引發的亂碼問題


字符集參考文獻:

http://dev.mysql.com/doc/refman/5.6/en/server-system-variables.html#sysvar_character_set_connection

http://dev.mysql.com/doc/refman/5.6/en/faqs-cjk.html

今天,一開發同事使用jdbc連接數據庫執行一條語句無結果集,但是通過sqlyou執行相同的語句有返回結果。

執行的語句where條件中含有中文,這應該是字符集引起的

此開發測試實例剛遷移不久的,查看遷移前的環境默認字符集都是utf8

查看當前數據庫的字符集

mysql> show variables like '%charac%';
+--------------------------+----------------------------------+
| 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/local/mysql/share/charsets/ |
+--------------------------+----------------------------------+
8 rows in set (0.00 sec)
  • character_set_client    
  • character_set_connection
  • character_set_results

   以上三個控制mysql client的字符集

  • character_set_database  

          設置數據庫的默認字符集

  • character_set_server    

          設置以上所有的默認字符集

發現server端的字符集和client端的全局字符集設置變量都是采用的默認值latin1

發現配置文件中沒有添加參數項  character-set-server=utf8

造成亂碼的原因:

數據存儲時的編碼解碼過程

jdbc=>character_set_client=>table character

每個環節的字符集編碼都是utf8,沒有轉碼過程

character_set_client變為latin1后,讀取數據的解碼過程為

jdbc<=character_set_client<=table character

表中存儲的是utf8編碼格式,判斷和character_set_client不一致則轉碼為latin1的二進制流,然后傳輸給遠端的客戶端,

客戶端jdbc通過設置的字符集展示結果,使用utf8展示latin1,所以出現了亂碼。

解決辦法

# character_set_filesystem 、character_set_system 、character_sets_dir除外都變更全局為utf8

所有的應用需要重連數據庫才能變更會話級別的字符集

對於在字符集設置為latin1期間插入的數據編碼存儲過程:

  • 在terminal(這里為jdbc客戶端)中使用輸入法輸入
  • terminal轉換成utf8二進制流
  • 二進制流通過MySQL客戶端傳輸到MySQL Server
  • Server通過character-set-client解碼
  • 判斷character-set-client和目標表的charset是否一致,character-set-client為latin1,目標表的字符集為utf8
  • 不一致則進行一次從client-charset到table-charset的一次字符編碼轉換,由latin1轉碼為utf8
  • 將轉換后的字符編碼二進制流存入文件中

測試這種情況下將 中間環節的character-set-client變更為utf8,是否會出現亂碼

mysql> show  variables like '%char%';      
+--------------------------+----------------------------------+
| Variable_name            | Value                            |
+--------------------------+----------------------------------+
| character_set_client     | latin1                           |
| character_set_connection | latin1                           |
| character_set_database   | utf8                             |
| character_set_filesystem | binary                           |
| character_set_results    | latin1                           |
| character_set_server     | utf8                             |
| character_set_system     | utf8                             |
| character_sets_dir       | /usr/local/mysql/share/charsets/ |
+--------------------------+----------------------------------+
8 rows in set (0.01 sec)

mysql> update t1 set col='建軍節' where id=4;    

mysql> select * from t1 where id=4;
+----+-----------+------+
| id | col       | time |
+----+-----------+------+
|  4 | 建軍節    | NULL |
+----+-----------+------+


解碼編碼轉儲

crt terminal =》character_set_client =》character_set_server
		utf8          latin1                 utf8			
如果查詢時任何一個環節的字符集變化都可能會造成亂碼
更改不同環節的字符集對應的數據顯示
1、改變客戶端的字符集
mysql> set names utf8;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t1 where id=4;
+----+-----------------------+------+
| id | col                   | time |
+----+-----------------------+------+
|  4 | ??o???è??             | NULL |
+----+-----------------------+------+
2、更改crt terminal 的字符集為default
mysql> select * from t1 where id=4;
+----+-----------+------+
| id | col       | time |
+----+-----------+------+
|  4 | 寤哄啗鑺   | NULL |
+----+-----------+------+
3、更改表字段字符集
ALTER TABLE t1 CHANGE col col varchar(10) CHARACTER SET latin1;

mysql> select * from t1 where id=4;
+----+-----------+------+
| id | col       | time |
+----+-----------+------+
|  4 | 建軍節    | NULL |
+----+-----------+------+

 更改表的字符集為latin1,讀取數據涉及到變更的環節變為

  • 從文件讀出二進制數據流(utf8存入)
  • 用表字符集latin1編碼進行解碼
  • 將數據轉換為character-set-client的編碼laint1

對應的變更前的環節:

  • 從文件讀出二進制數據流(utf8存入)
  • 用表字符集utf8編碼進行解碼
  • 將數據轉換為character-set-client的編碼laint1

可以看出更改表數據字符集沒有導致亂碼的原因是,字符集整體經歷的解碼和轉碼過程是一致的,都經歷了一次由utf8到latin1的轉碼。

另一有關字符集的問題:為了支持表情符號,將系統級別的utf8設置為utf8mb4且相應的表也做了字符集的轉變,重啟應用不生效,重啟數據庫和應用才會生效

參考文章為:

http://blog.sina.com.cn/s/blog_93b45b0f0101glfx.html

參考文章:

  編碼解碼過程  : http://cenalulu.github.io/mysql/mysql-mojibake/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM