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😈
表情。
[mysqld]
character_set_server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake
這三行配置就可以解決問題,最關鍵的是最後一行,參考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_unicode_ci |
| collation_database | utf8_unicode_ci |
| collation_server | utf8_unicode_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
參數。
參考資料
- MySQL連接校對:utf8_general_ci與utf8_unicode_ci有什麼區別呢 :https://segmentfault.com/q/10...
- Unicode 和 UTF-8 有什麼區別?:https://www.zhihu.com/questio...
- 深入Mysql字符集設置:http://www.laruence.com/2008/...
- 10.4 Connection Character Sets and Collations:https://dev.mysql.com/doc/ref...
- ISO/IEC 8859-1:https://zh.wikipedia.org/wiki...
- 5.1.6 Server Command Options:https://dev.mysql.com/doc/ref...
- 用service命令管理mysql啓停:https://segmentfault.com/a/11...
- Unicode字符集和UTF8編碼編碼的前世今生:https://segmentfault.com/a/11...
- Mysql中的排序規則utf8_unicode_ci、utf8_general_ci的區別總結:https://www.jb51.net/article/...