MySQL 字符集問題

MySQL的字符集和排序:

MySQL數據庫的字符集包含兩個基本概念:「字符集」和「排序」html

「字符集」的英文是 character set,簡稱 charset。mysql

「排序」的英文是 collate(動詞),collation(名詞)。sql

常見的字符集有:ascii、big五、bgk、latin一、utf8。數據庫

MySQL 5.3.3 中,加入了幾個新的字符集:utf1六、utf3二、utf8mb4。app

MySQL 中的 utf8 最多支持 3 字節的文字(實際上 utf8 是 utf8mb3 的別名),utf8mb4 最多支持 4 字節的文字。less

「字符集」是數據庫存儲字符時用的編碼格式,「排序」是使用 ORDER 或 WHERE a>100 等語句時,比較字符大小的方法。編碼

utf8mb4_general_ci、utf8mb4_unicode_ci、utf8mb4_bin。spa

bin 指二進制比較,general 指比較字符串的編碼值(實際比較的是 unicode 值)。code

unicode 在 general 的基礎上,增長了字母組合的處理,如德文中 ß 和 ss 是相同的。orm

下段摘自https://dev.mysql.com/doc/refman/8.0/en/charset-unicode-sets.html

For any Unicode character set, operations performed using the xxx_general_ci collation are faster than those for the xxx_unicode_ci collation. For example, comparisons for the utf8_general_ci collation are faster, but slightly less correct, than comparisons for utf8_unicode_ci. The reason is that utf8_unicode_ci supports mappings such as expansions; that is, when one character compares as equal to combinations of other characters. For example, ß is equal to ss in German and some other languages. utf8_unicode_ci also supports contractions and ignorable characters. utf8_general_ci is a legacy collation that does not support expansions, contractions, or ignorable characters. It can make only one-to-one comparisons between characters.

查看數據庫支持的字符集(MySQL 8.0):

mysql> show charset;

mysql> show character set;
+----------+---------------------------------+---------------------+--------+ | Charset | Description | Default collation | Maxlen | +----------+---------------------------------+---------------------+--------+ | armscii8 | ARMSCII-8 Armenian | armscii8_general_ci | 1 | | ascii | US ASCII | ascii_general_ci | 1 | | big5 | Big5 Traditional Chinese | big5_chinese_ci | 2 | | binary | Binary pseudo charset | binary | 1 | | cp1250 | Windows Central European | cp1250_general_ci | 1 | | cp1251 | Windows Cyrillic | cp1251_general_ci | 1 | | cp1256 | Windows Arabic | cp1256_general_ci | 1 | | cp1257 | Windows Baltic | cp1257_general_ci | 1 | | cp850 | DOS West European | cp850_general_ci | 1 | | cp852 | DOS Central European | cp852_general_ci | 1 | | cp866 | DOS Russian | cp866_general_ci | 1 | | cp932 | SJIS for Windows Japanese | cp932_japanese_ci | 2 | | dec8 | DEC West European | dec8_swedish_ci | 1 | | eucjpms | UJIS for Windows Japanese | eucjpms_japanese_ci | 3 | | euckr | EUC-KR Korean | euckr_korean_ci | 2 | | gb18030 | China National Standard GB18030 | gb18030_chinese_ci | 4 | | gb2312 | GB2312 Simplified Chinese | gb2312_chinese_ci | 2 | | gbk | GBK Simplified Chinese | gbk_chinese_ci | 2 | | geostd8 | GEOSTD8 Georgian | geostd8_general_ci | 1 | | greek | ISO 8859-7 Greek | greek_general_ci | 1 | | hebrew | ISO 8859-8 Hebrew | hebrew_general_ci | 1 | | hp8 | HP West European | hp8_english_ci | 1 | | keybcs2 | DOS Kamenicky Czech-Slovak | keybcs2_general_ci | 1 | | koi8r | KOI8-R Relcom Russian | koi8r_general_ci | 1 | | koi8u | KOI8-U Ukrainian | koi8u_general_ci | 1 | | latin1 | cp1252 West European | latin1_swedish_ci | 1 | | latin2 | ISO 8859-2 Central European | latin2_general_ci | 1 | | latin5 | ISO 8859-9 Turkish | latin5_turkish_ci | 1 | | latin7 | ISO 8859-13 Baltic | latin7_general_ci | 1 | | macce | Mac Central European | macce_general_ci | 1 | | macroman | Mac West European | macroman_general_ci | 1 | | sjis | Shift-JIS Japanese | sjis_japanese_ci | 2 | | swe7 | 7bit Swedish | swe7_swedish_ci | 1 | | tis620 | TIS620 Thai | tis620_thai_ci | 1 | | ucs2 | UCS-2 Unicode | ucs2_general_ci | 2 | | ujis | EUC-JP Japanese | ujis_japanese_ci | 3 | | utf16 | UTF-16 Unicode | utf16_general_ci | 4 | | utf16le | UTF-16LE Unicode | utf16le_general_ci | 4 | | utf32 | UTF-32 Unicode | utf32_general_ci | 4 | | utf8 | UTF-8 Unicode | utf8_general_ci | 3 | | utf8mb4 | UTF-8 Unicode | utf8mb4_0900_ai_ci | 4 | +----------+---------------------------------+---------------------+--------+ 41 rows in set (0.00 sec)

查看某個字符集支持的排序(MySQL 8.0):

mysql> show collation;
+----------------------------+----------+-----+---------+----------+---------+---------------+
| Collation                  | Charset  | Id  | Default | Compiled | Sortlen | Pad_attribute |
+----------------------------+----------+-----+---------+----------+---------+---------------+
| armscii8_bin               | armscii8 |  64 |         | Yes      |       1 | PAD SPACE     |

......      ......      ......      ......      ......      ......      ......      ..........

| utf8_vietnamese_ci         | utf8     | 215 |         | Yes      |       8 | PAD SPACE     |
+----------------------------+----------+-----+---------+----------+---------+---------------+
272 rows in set (0.00 sec)

latin1 支持的排序:

mysql> show collation like 'latin1%';
+-------------------+---------+----+---------+----------+---------+---------------+
| Collation         | Charset | Id | Default | Compiled | Sortlen | Pad_attribute |
+-------------------+---------+----+---------+----------+---------+---------------+
| latin1_bin        | latin1  | 47 |         | Yes      |       1 | PAD SPACE     |
| latin1_danish_ci  | latin1  | 15 |         | Yes      |       1 | PAD SPACE     |
| latin1_general_ci | latin1  | 48 |         | Yes      |       1 | PAD SPACE     |
| latin1_general_cs | latin1  | 49 |         | Yes      |       1 | PAD SPACE     |
| latin1_german1_ci | latin1  |  5 |         | Yes      |       1 | PAD SPACE     |
| latin1_german2_ci | latin1  | 31 |         | Yes      |       2 | PAD SPACE     |
| latin1_spanish_ci | latin1  | 94 |         | Yes      |       1 | PAD SPACE     |
| latin1_swedish_ci | latin1  |  8 | Yes     | Yes      |       1 | PAD SPACE     |
+-------------------+---------+----+---------+----------+---------+---------------+
8 rows in set (0.00 sec)

utf8mb4 支持的排序:

mysql> show collation like 'utf8mb4%';
+----------------------------+---------+-----+---------+----------+---------+---------------+
| Collation                  | Charset | Id  | Default | Compiled | Sortlen | Pad_attribute |
+----------------------------+---------+-----+---------+----------+---------+---------------+
| utf8mb4_0900_ai_ci         | utf8mb4 | 255 | Yes     | Yes      |       0 | NO PAD        |
| utf8mb4_0900_as_ci         | utf8mb4 | 305 |         | Yes      |       0 | NO PAD        |
| utf8mb4_0900_as_cs         | utf8mb4 | 278 |         | Yes      |       0 | NO PAD        |
| utf8mb4_0900_bin           | utf8mb4 | 309 |         | Yes      |       1 | NO PAD        |
| utf8mb4_bin                | utf8mb4 |  46 |         | Yes      |       1 | PAD SPACE     |
| utf8mb4_croatian_ci        | utf8mb4 | 245 |         | Yes      |       8 | PAD SPACE     |
| utf8mb4_cs_0900_ai_ci      | utf8mb4 | 266 |         | Yes      |       0 | NO PAD        |
| utf8mb4_cs_0900_as_cs      | utf8mb4 | 289 |         | Yes      |       0 | NO PAD        |
| utf8mb4_czech_ci           | utf8mb4 | 234 |         | Yes      |       8 | PAD SPACE     |
| utf8mb4_danish_ci          | utf8mb4 | 235 |         | Yes      |       8 | PAD SPACE     |
| utf8mb4_da_0900_ai_ci      | utf8mb4 | 267 |         | Yes      |       0 | NO PAD        |
| utf8mb4_da_0900_as_cs      | utf8mb4 | 290 |         | Yes      |       0 | NO PAD        |
| utf8mb4_de_pb_0900_ai_ci   | utf8mb4 | 256 |         | Yes      |       0 | NO PAD        |
| utf8mb4_de_pb_0900_as_cs   | utf8mb4 | 279 |         | Yes      |       0 | NO PAD        |
| utf8mb4_eo_0900_ai_ci      | utf8mb4 | 273 |         | Yes      |       0 | NO PAD        |
| utf8mb4_eo_0900_as_cs      | utf8mb4 | 296 |         | Yes      |       0 | NO PAD        |
| utf8mb4_esperanto_ci       | utf8mb4 | 241 |         | Yes      |       8 | PAD SPACE     |
| utf8mb4_estonian_ci        | utf8mb4 | 230 |         | Yes      |       8 | PAD SPACE     |
| utf8mb4_es_0900_ai_ci      | utf8mb4 | 263 |         | Yes      |       0 | NO PAD        |
| utf8mb4_es_0900_as_cs      | utf8mb4 | 286 |         | Yes      |       0 | NO PAD        |
| utf8mb4_es_trad_0900_ai_ci | utf8mb4 | 270 |         | Yes      |       0 | NO PAD        |
| utf8mb4_es_trad_0900_as_cs | utf8mb4 | 293 |         | Yes      |       0 | NO PAD        |
| utf8mb4_et_0900_ai_ci      | utf8mb4 | 262 |         | Yes      |       0 | NO PAD        |
| utf8mb4_et_0900_as_cs      | utf8mb4 | 285 |         | Yes      |       0 | NO PAD        |
| utf8mb4_general_ci         | utf8mb4 |  45 |         | Yes      |       1 | PAD SPACE     |
| utf8mb4_german2_ci         | utf8mb4 | 244 |         | Yes      |       8 | PAD SPACE     |
| utf8mb4_hr_0900_ai_ci      | utf8mb4 | 275 |         | Yes      |       0 | NO PAD        |
| utf8mb4_hr_0900_as_cs      | utf8mb4 | 298 |         | Yes      |       0 | NO PAD        |
| utf8mb4_hungarian_ci       | utf8mb4 | 242 |         | Yes      |       8 | PAD SPACE     |
| utf8mb4_hu_0900_ai_ci      | utf8mb4 | 274 |         | Yes      |       0 | NO PAD        |
| utf8mb4_hu_0900_as_cs      | utf8mb4 | 297 |         | Yes      |       0 | NO PAD        |
| utf8mb4_icelandic_ci       | utf8mb4 | 225 |         | Yes      |       8 | PAD SPACE     |
| utf8mb4_is_0900_ai_ci      | utf8mb4 | 257 |         | Yes      |       0 | NO PAD        |
| utf8mb4_is_0900_as_cs      | utf8mb4 | 280 |         | Yes      |       0 | NO PAD        |
| utf8mb4_ja_0900_as_cs      | utf8mb4 | 303 |         | Yes      |       0 | NO PAD        |
| utf8mb4_ja_0900_as_cs_ks   | utf8mb4 | 304 |         | Yes      |      24 | NO PAD        |
| utf8mb4_latvian_ci         | utf8mb4 | 226 |         | Yes      |       8 | PAD SPACE     |
| utf8mb4_la_0900_ai_ci      | utf8mb4 | 271 |         | Yes      |       0 | NO PAD        |
| utf8mb4_la_0900_as_cs      | utf8mb4 | 294 |         | Yes      |       0 | NO PAD        |
| utf8mb4_lithuanian_ci      | utf8mb4 | 236 |         | Yes      |       8 | PAD SPACE     |
| utf8mb4_lt_0900_ai_ci      | utf8mb4 | 268 |         | Yes      |       0 | NO PAD        |
| utf8mb4_lt_0900_as_cs      | utf8mb4 | 291 |         | Yes      |       0 | NO PAD        |
| utf8mb4_lv_0900_ai_ci      | utf8mb4 | 258 |         | Yes      |       0 | NO PAD        |
| utf8mb4_lv_0900_as_cs      | utf8mb4 | 281 |         | Yes      |       0 | NO PAD        |
| utf8mb4_persian_ci         | utf8mb4 | 240 |         | Yes      |       8 | PAD SPACE     |
| utf8mb4_pl_0900_ai_ci      | utf8mb4 | 261 |         | Yes      |       0 | NO PAD        |
| utf8mb4_pl_0900_as_cs      | utf8mb4 | 284 |         | Yes      |       0 | NO PAD        |
| utf8mb4_polish_ci          | utf8mb4 | 229 |         | Yes      |       8 | PAD SPACE     |
| utf8mb4_romanian_ci        | utf8mb4 | 227 |         | Yes      |       8 | PAD SPACE     |
| utf8mb4_roman_ci           | utf8mb4 | 239 |         | Yes      |       8 | PAD SPACE     |
| utf8mb4_ro_0900_ai_ci      | utf8mb4 | 259 |         | Yes      |       0 | NO PAD        |
| utf8mb4_ro_0900_as_cs      | utf8mb4 | 282 |         | Yes      |       0 | NO PAD        |
| utf8mb4_ru_0900_ai_ci      | utf8mb4 | 306 |         | Yes      |       0 | NO PAD        |
| utf8mb4_ru_0900_as_cs      | utf8mb4 | 307 |         | Yes      |       0 | NO PAD        |
| utf8mb4_sinhala_ci         | utf8mb4 | 243 |         | Yes      |       8 | PAD SPACE     |
| utf8mb4_sk_0900_ai_ci      | utf8mb4 | 269 |         | Yes      |       0 | NO PAD        |
| utf8mb4_sk_0900_as_cs      | utf8mb4 | 292 |         | Yes      |       0 | NO PAD        |
| utf8mb4_slovak_ci          | utf8mb4 | 237 |         | Yes      |       8 | PAD SPACE     |
| utf8mb4_slovenian_ci       | utf8mb4 | 228 |         | Yes      |       8 | PAD SPACE     |
| utf8mb4_sl_0900_ai_ci      | utf8mb4 | 260 |         | Yes      |       0 | NO PAD        |
| utf8mb4_sl_0900_as_cs      | utf8mb4 | 283 |         | Yes      |       0 | NO PAD        |
| utf8mb4_spanish2_ci        | utf8mb4 | 238 |         | Yes      |       8 | PAD SPACE     |
| utf8mb4_spanish_ci         | utf8mb4 | 231 |         | Yes      |       8 | PAD SPACE     |
| utf8mb4_sv_0900_ai_ci      | utf8mb4 | 264 |         | Yes      |       0 | NO PAD        |
| utf8mb4_sv_0900_as_cs      | utf8mb4 | 287 |         | Yes      |       0 | NO PAD        |
| utf8mb4_swedish_ci         | utf8mb4 | 232 |         | Yes      |       8 | PAD SPACE     |
| utf8mb4_tr_0900_ai_ci      | utf8mb4 | 265 |         | Yes      |       0 | NO PAD        |
| utf8mb4_tr_0900_as_cs      | utf8mb4 | 288 |         | Yes      |       0 | NO PAD        |
| utf8mb4_turkish_ci         | utf8mb4 | 233 |         | Yes      |       8 | PAD SPACE     |
| utf8mb4_unicode_520_ci     | utf8mb4 | 246 |         | Yes      |       8 | PAD SPACE     |
| utf8mb4_unicode_ci         | utf8mb4 | 224 |         | Yes      |       8 | PAD SPACE     |
| utf8mb4_vietnamese_ci      | utf8mb4 | 247 |         | Yes      |       8 | PAD SPACE     |
| utf8mb4_vi_0900_ai_ci      | utf8mb4 | 277 |         | Yes      |       0 | NO PAD        |
| utf8mb4_vi_0900_as_cs      | utf8mb4 | 300 |         | Yes      |       0 | NO PAD        |
| utf8mb4_zh_0900_as_cs      | utf8mb4 | 308 |         | Yes      |       0 | NO PAD        |
+----------------------------+---------+-----+---------+----------+---------+---------------+
75 rows in set (0.00 sec)

上表中能夠看出,latin1 的默認排序是 latin1_swedish_ci,utf8mb4 的默認排序是 utf8mb4_0900_ai_ci。

對於字符集的設置,有幾個級別:

  • 數據庫程序實例級別(指一個運行着的數據庫進程)
  • 數據庫級別
  • 數據表級別
  • 數據列級別
  • SQL 語句級別

優先級依次遞增

對於數據庫實例級別的設置,有兩個方法:

一、修改 my.cnf 文件:

character_set_server=utf8mb4
; 若是沒設置 character_set_server,MySQL 8.0 以前默認是 latin1,MySQL 8.0 及以後默認是 utf8mb4
collation=utf8mb4_0900_ai_ci
; 若是沒設置 collation,則使用字符集的默認排序
; latin1 的默認排序是 latin1_swedish_ci,utf8mb4 的默認排序是 utf8mb4_0900_ai_ci

 二、啓動服務時設定

mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_0900_ai_ci

這兩個我都沒試過,由於新建數據庫和新建數據表時,最好顯式提供 character set 和 collation,數據庫實例級別的設置對咱們沒有任何影響。

 對於數據庫級別的設置(MySQL 5.7):

 下例:MySQL 5.7 默認字符集是 latin1,新建數據庫時,不指定字符集,便使用默認字符集 latin1。

mysql> create database mytest;
Query OK, 1 row affected

mysql> show create database mytest;
+----------+-------------------------------------------------------------------+
| Database | Create Database                                                   |
+----------+-------------------------------------------------------------------+
| mytest   | CREATE DATABASE `mytest` /*!40100 DEFAULT CHARACTER SET latin1 */ |
+----------+-------------------------------------------------------------------+
1 row in set

mysql> drop database mytest;
Query OK, 0 rows affected

下例:新建數據庫時,指定字符集爲 utf8mb4。

mysql> create database mytest default character set utf8mb4;
Query OK, 1 row affected

mysql> show create database mytest;
+----------+--------------------------------------------------------------------+
| Database | Create Database                                                    |
+----------+--------------------------------------------------------------------+
| mytest   | CREATE DATABASE `mytest` /*!40100 DEFAULT CHARACTER SET utf8mb4 */ |
+----------+--------------------------------------------------------------------+
1 row in set

mysql> drop database mytest;
Query OK, 0 rows affected

下例:新建數據庫時,指定字符集爲 utf8mb4,指定排序爲 utf8mb4_general_ci(MySQL 8.0 以前,沒有 utf8mb4_0900_ai_ci)。

數據庫 DDL 不顯示默認排序規則。

mysql> create database mytest default character set utf8mb4 collate utf8mb4_general_ci;
Query OK, 1 row affected

mysql> show create database mytest;
+----------+--------------------------------------------------------------------+
| Database | Create Database                                                    |
+----------+--------------------------------------------------------------------+
| mytest   | CREATE DATABASE `mytest` /*!40100 DEFAULT CHARACTER SET utf8mb4 */ |
+----------+--------------------------------------------------------------------+
1 row in set

mysql> drop database mytest;
Query OK, 0 rows affected

下例:新建數據庫時,指定字符集爲 utf8mb4,指定排序爲 utf8mb4_bin。

mysql> create database mytest default character set utf8mb4 collate utf8mb4_bin;
Query OK, 1 row affected

mysql> show create database mytest;
+----------+----------------------------------------------------------------------------------------+
| Database | Create Database                                                                        |
+----------+----------------------------------------------------------------------------------------+
| mytest   | CREATE DATABASE `mytest` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin */ |
+----------+----------------------------------------------------------------------------------------+
1 row in set

mysql> drop database mytest;
Query OK, 0 rows affected

 下例:修改已有數據庫的字符集和排序。

mysql> alter database mytest default character set utf8mb4;
Query OK, 1 row affected

mysql> alter database mytest collate utf8mb4_bin;
Query OK, 1 row affected

mysql> alter database mytest default character set utf8mb4 collate utf8mb4_bin;
Query OK, 1 row affected

數據表級別

TODO

數據列級別

TODO

SQL 語句級別

TODO

 

 數據庫中字符集相關的幾個變量:

 

MySQL [(none)]> show variables like '%char%';                                   mysql> show variables like '%char%';
+--------------------------+-----------------------------------------------+    +--------------------------+-----------------------------------------------+
| Variable_name            | Value                                         |    | Variable_name            | Value                                         |
+--------------------------+-----------------------------------------------+    +--------------------------+-----------------------------------------------+
| character_set_client     | utf8                                          |    | character_set_client     | gbk                                           |
| character_set_connection | utf8                                          |    | character_set_connection | gbk                                           |
| character_set_database   | latin1                                        |    | character_set_database   | latin1                                        |
| character_set_filesystem | binary                                        |    | character_set_filesystem | binary                                        |
| character_set_results    | utf8                                          |    | character_set_results    | gbk                                           |
| character_set_server     | latin1                                        |    | character_set_server     | latin1                                        |
| character_set_system     | utf8                                          |    | character_set_system     | utf8                                          |
| character_sets_dir       | d:\wamp\bin\mysql\mysql5.7.24\share\charsets\ |    | character_sets_dir       | d:\wamp\bin\mysql\mysql5.7.24\share\charsets\ |
+--------------------------+-----------------------------------------------+    +--------------------------+-----------------------------------------------+
8 rows in set, 1 warning (0.006 sec)                                            8 rows in set, 1 warning (0.01 sec)

MySQL [(none)]> use mytest;                                                     mysql> use mytest;
Database changed                                                                Database changed
                                                                                
MySQL [mytest]> show variables like '%char%';                                   mysql> show variables like '%char%';
+--------------------------+-----------------------------------------------+    +--------------------------+-----------------------------------------------+
| Variable_name            | Value                                         |    | Variable_name            | Value                                         |
+--------------------------+-----------------------------------------------+    +--------------------------+-----------------------------------------------+
| character_set_client     | utf8                                          |    | character_set_client     | gbk                                           |
| character_set_connection | utf8                                          |    | character_set_connection | gbk                                           |
| character_set_database   | utf8mb4                                       |    | character_set_database   | utf8mb4                                       |
| character_set_filesystem | binary                                        |    | character_set_filesystem | binary                                        |
| character_set_results    | utf8                                          |    | character_set_results    | gbk                                           |
| character_set_server     | latin1                                        |    | character_set_server     | latin1                                        |
| character_set_system     | utf8                                          |    | character_set_system     | utf8                                          |
| character_sets_dir       | d:\wamp\bin\mysql\mysql5.7.24\share\charsets\ |    | character_sets_dir       | d:\wamp\bin\mysql\mysql5.7.24\share\charsets\ |
+--------------------------+-----------------------------------------------+    +--------------------------+-----------------------------------------------+
8 rows in set, 1 warning (0.007 sec)                                            8 rows in set, 1 warning (0.00 sec)

 上例:

使用MySQL 5.7。

左側展現使用 Cygwin 鏈接的操做結果,右側展現使用 cmd 鏈接的操做結果。

能夠看出: character_set_client 、 character_set_connection 、 character_set_results  三個變量,跟客戶端使用的字符集有關。Cygwin 使用 utf8 字符集,這三個變量就是 utf8,cmd 使用 gbk 字符集,這三個變量就是 bgk。

 character_set_server  變量:此變量是數據庫實例級別的字符集設置值。

 character_set_database  變量:此變量是數據庫級別的字符集設置值。此實例中,第一次執行 show variables like '%char%'; 時,還未選擇任何數據庫,此變量值默認等於  character_set_server  ,即 latin1 。選擇 mytest 數據庫後,此變量變爲 mytest 數據庫的字符集設置,即 utf8mb4 。

亂碼是怎樣產生的(我的理解)

爲方便說明,如下提到字符集時,同一個數據庫中,數據表、數據列使用與數據庫相同的字符集。

數據庫相關的亂碼,產生的時機有兩個:一是往數據庫中存儲時產生,二是從數據庫中取出時產生。

數據庫爲保證內部編碼的正確性,使客戶端的字符集與服務端的字符集無關。

大致流程是:

寫入數據庫時:

  1. 經過  character_set_client  判斷客戶端使用的字符集 charset_from
  2. 經過 character_set_server 、 character_set_database 、數據表、數據列、SQL語句的優先級,肯定數據存儲時使用的字符集charset_to
  3. 把客戶端傳入的字符數據,由charset_from 轉換爲charset_to ,存儲在數據庫文件中

讀取數據庫時:

  1. 經過 character_set_server 、 character_set_database 、數據庫、數據列、SQL語句的優先級,肯定數據存儲時使用的字符集 charset_from 
  2. 經過 character_set_results (注意不是 character_set_client )判斷客戶端但願收到的字符集 charset_to 
  3. 把查詢結果中的字符數據,由 charset_from 轉換爲 charset_to ,返回給客戶端

從流程上能夠看出,客戶端使用什麼樣的字符集,與數據庫使用什麼樣的字符集,是無關的(不考慮轉換不成功不能存儲的問題)。

只要數據庫設置爲 utf8mb4(能夠存儲全部現有字符),客戶端  set names ******; 設置好客戶端使用的字符集, 不存在亂碼問題。

如今主流版本的 MySQL(服務端和客戶端配合使用),在存入字符時,會作字符有效性檢查,在必定程度上保證存入字符的正確性。下例左側服務端和客戶端爲 MySQL 5.0.77,右側服務端和客戶端爲 MySQL 5.7.24:

客戶端均使用cmd(gbk)
mysql> show variables like 'version'; mysql> show variables like 'version'; +---------------+------------------+ +---------------+--------+ | Variable_name | Value | | Variable_name | Value | +---------------+------------------+ +---------------+--------+ | version | 5.0.77-community | | version | 5.7.24 | +---------------+------------------+ +---------------+--------+ 1 row in set (0.00 sec) 1 row in set, 1 warning (0.01 sec) mysql> create database mytest default character set latin1; mysql> create database mytest default character set latin1; Query OK, 1 row affected (0.00 sec) Query OK, 1 row affected (0.00 sec) mysql> use mytest; mysql> use mytest; Database changed Database changed mysql> create table mytable (name text); mysql> create table mytable (name text); Query OK, 0 rows affected (0.02 sec) Query OK, 0 rows affected (0.07 sec) mysql> insert into mytable (name) values ('中文'); mysql> insert into mytable (name) values ('中文'); Query OK, 1 row affected (0.00 sec) ERROR 1366 (HY000): Incorrect string value: '\xD6\xD0\xCE\xC4' for column 'name' at row 1 mysql> select * from mytable; mysql> select * from mytable; +------+ Empty set (0.00 sec) | name | +------+ | 中文 | +------+ 1 row in set (0.00 sec)

 

左側的 MySQL 5.0.77,能夠存入中文,能夠取出中文。

可是,存入的字符串是從 gbk 轉爲 latin1 (實際是不能轉換成功的,我的認爲這種轉換是將每一個漢字的兩個 gbk 字節轉爲兩個單字節存入數據庫),以亂碼的方式存到數據庫當中的(轉換後的單字節不少不存在於 latin1 字符集)。

取出來時,又進行了一次轉換(每遇到兩個字節,轉換爲一個 gbk 字符)。因爲客戶端使用 gbk 字符集,因此碰巧顯示成功。

使用 Cygwin(utf8)讀取一下剛纔存入的中文:

MySQL [mytest]> select * from mytable;
+----------+
| name     |
+----------+
| ÖÐÎÄ     |
+----------+
1 row in set (0.000 sec)

 




我曾經覺得,使用不一樣字符編碼的客戶端,操做同一個數據庫,會出現各類問題。

直到最近才搞清楚,數據庫設置好(須要存儲中文的庫、表、列,設置爲 utf8mb4 等能夠存儲全部字符的字符集),客戶端搞清楚本身使用的字符編碼(本身是 gbk 就不要非把本身設置爲 utf8 ,hold 不住),服務端和客戶端各司其職,將不會出現亂碼問題。

相關文章
相關標籤/搜索