MySQL亂碼的原因和設置UTF8數據格式

MySQL使用時,有一件很痛苦的事情肯定是結果亂碼。將編碼格式都設置為UTF8可以解決這個問題,我們今天來說下為什么要這么設置,以及怎么設置。

MySQL字符格式

字符集

在編程語言中,我們為了防止中文亂碼,會使用unicode對中文字符做處理,而為了降低網絡帶寬和節省存儲空間,我們使用UTF8進行編碼。對這兩者有什么不同不夠了解的同學,可以參考Unicode字符集和UTF8編碼編碼的前世今生這篇文章。

同樣在MySQL中,我們也會有這樣的處理,我們可以查看當前數據庫設置的編碼方式(字符集):

````mysql> show variables like '%char%';

+--------------------------+----------------------------------+

| Variable_name | Value |

+--------------------------+----------------------------------+

| character_set_client | latin1 |

| character_set_connection | latin1 |

| character_set_database | latin1 |

| character_set_filesystem | binary |

| character_set_results | latin1 |

| 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_filesystem | binary:文件系統上的存儲格式,默認為binary(二進制)

character_set_system | utf8:系統的存儲格式,默認為utf8

character_sets_dir | /usr/local/mysql/share/charsets/:可以使用的字符集的文件路徑

剩下的幾個就是日常影響讀寫亂碼的參數了:

- character_set_client:客戶端請求數據的字符集

- character_set_connection:從客戶端接收到數據,然后傳輸的字符集

- character_set_database:默認數據庫的字符集;如果沒有默認數據庫,使用character_set_server字段

- character_set_results:結果集的字符集

- character_set_server:數據庫服務器的默認字符集

字符集的轉換流程分為3步:

客戶端請求數據庫數據,發送的數據使用character_set_client字符集

MySQL實例收到客戶端發送的數據后,將其轉換為character_set_connection字符集

進行內部操作時,將數據字符集轉換為內部操作字符集:

使用每個數據字段的character set設定值

若不存在,使用對應數據表的default character set設定值

若不存在,使用對應數據庫的default character set設定值

若不存在,使用character_set_server設定值

將操作結果值從內部操作字符集轉換為character_set_results

字符序

說字符序之前,我們需要了解一點基礎知識:

字符(Character)是指人類語言中最小的表義符號。例如’A’、’B’等;

給定一系列字符,對每個字符賦予一個數值,用數值來代表對應的字符,這一數值就是字符的編碼(Encoding)。例如,我們給字符’A’賦予數值0,給字符’B’賦予數值1,則0就是字符’A’的編碼;

給定一系列字符并賦予對應的編碼后,所有這些字符和編碼對組成的集合就是字符集(Character Set)。例如,給定字符列表為{‘A’,’B’}時,{‘A’=>0, ‘B’=>1}就是一個字符集;

字符序(Collation)是指在同一字符集內字符之間的比較規則;

確定字符序后,才能在一個字符集上定義什么是等價的字符,以及字符之間的大小關系;

每個字符序唯一對應一種字符集,但一個字符集可以對應多種字符序,其中有一個是默認字符序(Default Collation);

MySQL中的字符序名稱遵從命名慣例:以字符序對應的字符集名稱開頭;以_ci(表示大小寫不敏感,case insensitive)、_cs(表示大小寫敏感,case sensitive)或_bin(表示按編碼值比較,binary)結尾。例如:在字符序“utf8_general_ci”下,字符“a”和“A”是等價的;

因此字符序不同于字符集,用于數據庫字段的相等或大小比較。我們查看MySQL實例設置的字符序:

````mysql> show variables like 'collation%';

+----------------------+-------------------+

| Variable_name | Value |

+----------------------+-------------------+

| collation_connection | latin1_swedish_ci |

| collation_database | latin1_swedish_ci |

| collation_server | latin1_swedish_ci |

+----------------------+-------------------+

3 rows in set (0.00 sec)````

跟utf8對應的常用字符序是:utf8_unicode_ci/utf8_general_ci和utf8_bin等,那么他們的區別是什么呢?

_bin是用二進制存儲并比較,區別大小寫,存儲二進制內容時使用

utf8_general_ci:校對速度快,但準確度稍差,使用中英文時使用

utf8_unicode_ci:準確度高,但校對速度稍慢,使用德法俄等外語時使用

詳細的區別可以參考 Mysql中的排序規則utf8_unicode_ci、utf8_general_ci的區別總結。

修改字符集和字符序

如果在MySQL連接時,出現了亂碼的問題,那么基本可以確定是各個字符集/序設置不統一的原因。MySQL默認的latin1格式不支持中文,由于我們在中國,所以選擇對中文和各語言支持都非常完善的utf8格式。所以,我們需要將需要關注的字符集和字符序都修改為utf8格式。

你也可以選擇utf8mb4格式,這個格式支持保存emoji表情。

我們需要修改Mysql的配置文件,查看配置文件的位置有兩種方式:

````1. $ mysql --help | grep 'my.cnf'

/etc/mysql/my.cnf /etc/my.cnf ~/.my.cnf

2. ps aux | grep mysql````

在(1)中,/etc/my.cnf, /etc/mysql/my.cnf, ~/.my.cnf 這些就是mysql默認會搜尋my.cnf的目錄,優先級依次升高。可以在各個配置文件里都使用long_query_time 來測試一下。

然后,我們修改或新增下面的配置項:

# 下面注釋的幾行可以不設置,但如果你的沒有生效,也可以試試看

````[mysqld]

character_set_server=utf8

collation-server=utf8_general_ci

skip-character-set-client-handshake

#init_connect='SET NAMES utf8'

#[client]

#default-character-set=utf8````

這三行配置就可以解決問題,最關鍵的是最后一行,參考mysql文檔,使用該參數會忽略客戶端傳遞的字符集信息,而直接使用服務端的設定;再加上我們設定服務端的字符集和字符序均為utf8,這樣就保證了字符格式的統一,解決亂碼的問題。

重啟mysql服務,如果提示找不到服務,請參考用service命令管理mysql啟停:

````$ service mysqld restart

Shutting down MySQL.. [ OK ]

Starting MySQL. [ OK ]

連接到mysql,查看當前編碼:

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/local/mysql/share/charsets/ |

+--------------------------+----------------------------------+

8 rows in set (0.01 sec)

mysql> show variables like 'collation%';

+----------------------+-----------------+

| Variable_name | Value |

+----------------------+-----------------+

| collation_connection | utf8_general_ci |

| collation_database | utf8_general_ci |

| collation_server | utf8_general_ci |

+----------------------+-----------------+

3 rows in set (0.01 sec)````

可以看到一切都符合預期,請求和存儲的數據也不再是亂碼了。

遇到的問題

unknown variable 'default-character-set=utf8'

參考官方文檔,該參數自5.5.3版本廢棄,改為了character-set-server,改為這個參數即可。

但這個是在[mysqld]下的配置,在[client]下的配置依然使用default-character-set參數。


獲取以上Java高級架構最新視頻,歡迎

加入Java進階架構交流群:142019080。直接點擊鏈接加群。

https://jq.qq.com/?_wv=1027&k=5lXBNZ7

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容