任何計算機存儲數據,都需要字符集,因為計算機存儲的數據其實都是二進制編碼,將一個個字符,映射到對應的二進制編碼的這個映射就是字符編碼(字符集)。這些字符如何排序呢?決定字符排序的規則就是排序規則。
查看內置字符集與比較規則
通過show charset;
命令,可以查看所有的字符集。
以下僅展示了我們常用的字符集:
+----------+---------------------------------+---------------------+--------+
| Charset | Description | Default collation | Maxlen |
+----------+---------------------------------+---------------------+--------+
| latin1 | cp1252 West European | latin1_swedish_ci | 1 |
| ascii | US ASCII | ascii_general_ci | 1 |
| gb2312 | GB2312 Simplified Chinese | gb2312_chinese_ci | 2 |
| cp1250 | Windows Central European | cp1250_general_ci | 1 |
| gbk | GBK Simplified Chinese | gbk_chinese_ci | 2 |
| utf8 | UTF-8 Unicode | utf8_general_ci | 3 |
| utf8mb4 | UTF-8 Unicode | utf8mb4_general_ci | 4 |
| utf16 | UTF-16 Unicode | utf16_general_ci | 4 |
| utf32 | UTF-32 Unicode | utf32_general_ci | 4 |
+----------+---------------------------------+---------------------+--------+
ascii
:共收錄128個字符,包括空格、標點符號、數字、大小寫字母和一些不可見字符。由於總共才128個字符,所以可以使用1個字節來進行編碼latin1
:共收錄256個字符,是在ASCII字符集的基礎上又擴充了128個西歐常用字符(包括德法兩國的字母),也可以使用1個字節來進行編碼。gb2312
: 收錄了漢字以及拉丁字母、希臘字母、日文平假名及片假名字母、俄語西里爾字母。其中收錄漢字6763個,其他文字符號682個,兼容ASCII字符集。這是一個變長字符集,如果該字符在ascii
字符集中,則采用1字節編碼,否則采用兩字節。gbk
: GBK是在gb2312
基礎上擴容后的標准。收錄了所有的中文字符。同樣的,這是一個變長字符集,如果該字符在ascii
字符集中,則采用1字節編碼,否則采用兩字節。utf8
和utf8mb4
: 收錄地球上能想到的所有字符,而且還在不斷擴充。這種字符集兼容ASCII字符集,采用變長編碼方式,編碼一個字符需要使用1~4個字節。MySQL
為了節省空間,其中的utf8
是標准 UTF8 閹割后的,只有1~3字節編碼的字符集,基本包含了所有常用的字符。如果還要使用 enoji 表情,那么需要使用utf8mb4
,這個是完整的 UTF8 字符集。utf16
: 不同於utf8
,utf16
用兩個字節或者四個字節編碼字符,可以理解為utf8
的不節省空間的一種形式utf32
: 固定用四個字節編碼字符,可以理解為utf8
的不節省空間的一種形式
通過查看information_schema.character_sets
表,也可以看到所有的字符集:
mysql> select * from information_schema.character_sets where character_set_name = "utf8";
+--------------------+----------------------+---------------+--------+
| CHARACTER_SET_NAME | DEFAULT_COLLATE_NAME | DESCRIPTION | MAXLEN |
+--------------------+----------------------+---------------+--------+
| utf8 | utf8_general_ci | UTF-8 Unicode | 3 |
+--------------------+----------------------+---------------+--------+
1 row in set (0.06 sec)
通過show collation;
命令,可以查看所有的字符集,我們這里來查看utf8mb4
的排序規則:
mysql> show collation like 'utf8mb4%';
+------------------------+---------+-----+---------+----------+---------+
| Collation | Charset | Id | Default | Compiled | Sortlen |
+------------------------+---------+-----+---------+----------+---------+
| utf8mb4_general_ci | utf8mb4 | 45 | Yes | Yes | 1 |
| utf8mb4_bin | utf8mb4 | 46 | | Yes | 1 |
| utf8mb4_unicode_ci | utf8mb4 | 224 | | Yes | 8 |
| utf8mb4_icelandic_ci | utf8mb4 | 225 | | Yes | 8 |
| utf8mb4_latvian_ci | utf8mb4 | 226 | | Yes | 8 |
| utf8mb4_romanian_ci | utf8mb4 | 227 | | Yes | 8 |
| utf8mb4_slovenian_ci | utf8mb4 | 228 | | Yes | 8 |
| utf8mb4_polish_ci | utf8mb4 | 229 | | Yes | 8 |
| utf8mb4_estonian_ci | utf8mb4 | 230 | | Yes | 8 |
| utf8mb4_spanish_ci | utf8mb4 | 231 | | Yes | 8 |
| utf8mb4_swedish_ci | utf8mb4 | 232 | | Yes | 8 |
| utf8mb4_turkish_ci | utf8mb4 | 233 | | Yes | 8 |
| utf8mb4_czech_ci | utf8mb4 | 234 | | Yes | 8 |
| utf8mb4_danish_ci | utf8mb4 | 235 | | Yes | 8 |
| utf8mb4_lithuanian_ci | utf8mb4 | 236 | | Yes | 8 |
| utf8mb4_slovak_ci | utf8mb4 | 237 | | Yes | 8 |
| utf8mb4_spanish2_ci | utf8mb4 | 238 | | Yes | 8 |
| utf8mb4_roman_ci | utf8mb4 | 239 | | Yes | 8 |
| utf8mb4_persian_ci | utf8mb4 | 240 | | Yes | 8 |
| utf8mb4_esperanto_ci | utf8mb4 | 241 | | Yes | 8 |
| utf8mb4_hungarian_ci | utf8mb4 | 242 | | Yes | 8 |
| utf8mb4_sinhala_ci | utf8mb4 | 243 | | Yes | 8 |
| utf8mb4_german2_ci | utf8mb4 | 244 | | Yes | 8 |
| utf8mb4_croatian_ci | utf8mb4 | 245 | | Yes | 8 |
| utf8mb4_unicode_520_ci | utf8mb4 | 246 | | Yes | 8 |
| utf8mb4_vietnamese_ci | utf8mb4 | 247 | | Yes | 8 |
+------------------------+---------+-----+---------+----------+---------+
26 rows in set (0.13 sec)
同樣的,通過查詢information_schema.collations
也可以:
mysql> select * from information_schema.collations where character_set_name = "utf8mb4";
+------------------------+--------------------+-----+------------+-------------+---------+
| COLLATION_NAME | CHARACTER_SET_NAME | ID | IS_DEFAULT | IS_COMPILED | SORTLEN |
+------------------------+--------------------+-----+------------+-------------+---------+
| utf8mb4_general_ci | utf8mb4 | 45 | Yes | Yes | 1 |
| utf8mb4_bin | utf8mb4 | 46 | | Yes | 1 |
| utf8mb4_unicode_ci | utf8mb4 | 224 | | Yes | 8 |
| utf8mb4_icelandic_ci | utf8mb4 | 225 | | Yes | 8 |
| utf8mb4_latvian_ci | utf8mb4 | 226 | | Yes | 8 |
| utf8mb4_romanian_ci | utf8mb4 | 227 | | Yes | 8 |
| utf8mb4_slovenian_ci | utf8mb4 | 228 | | Yes | 8 |
| utf8mb4_polish_ci | utf8mb4 | 229 | | Yes | 8 |
| utf8mb4_estonian_ci | utf8mb4 | 230 | | Yes | 8 |
| utf8mb4_spanish_ci | utf8mb4 | 231 | | Yes | 8 |
| utf8mb4_swedish_ci | utf8mb4 | 232 | | Yes | 8 |
| utf8mb4_turkish_ci | utf8mb4 | 233 | | Yes | 8 |
| utf8mb4_czech_ci | utf8mb4 | 234 | | Yes | 8 |
| utf8mb4_danish_ci | utf8mb4 | 235 | | Yes | 8 |
| utf8mb4_lithuanian_ci | utf8mb4 | 236 | | Yes | 8 |
| utf8mb4_slovak_ci | utf8mb4 | 237 | | Yes | 8 |
| utf8mb4_spanish2_ci | utf8mb4 | 238 | | Yes | 8 |
| utf8mb4_roman_ci | utf8mb4 | 239 | | Yes | 8 |
| utf8mb4_persian_ci | utf8mb4 | 240 | | Yes | 8 |
| utf8mb4_esperanto_ci | utf8mb4 | 241 | | Yes | 8 |
| utf8mb4_hungarian_ci | utf8mb4 | 242 | | Yes | 8 |
| utf8mb4_sinhala_ci | utf8mb4 | 243 | | Yes | 8 |
| utf8mb4_german2_ci | utf8mb4 | 244 | | Yes | 8 |
| utf8mb4_croatian_ci | utf8mb4 | 245 | | Yes | 8 |
| utf8mb4_unicode_520_ci | utf8mb4 | 246 | | Yes | 8 |
| utf8mb4_vietnamese_ci | utf8mb4 | 247 | | Yes | 8 |
+------------------------+--------------------+-----+------------+-------------+---------+
26 rows in set (0.11 sec)
- 每個字符集都有一個默認的排序規則:IS_DEFAULT 為 Yes。
- 比較規則名稱以與其關聯的字符集的名稱開頭,可以用通過這個開頭查詢所有的字符集,也可以查詢
information_schema.collations
精確指定字符集 - 字符集后面跟着的是語言編碼,因為
utf8mb4
包含了所有字符,不同國家的文字語言排序肯定不一樣。 - 最后末尾的
ci
代表case insensitive
,大小寫不敏感,所有可能的后綴如下所示:- ai: accent insensitive 不區分重音
- as: accent sensitive 區分重音
- ci: case insensitive 不區分大小寫
- cs: case sensitive 區分大小寫
- bin: binary 以二進制方式比較
應用字符集與比較規則
字符集與比較規則配置有四個級別:
- MySQL實例級別
- 庫級別
- 表級別
- 字段級別
指定的級別粒度越小,則以粒度越小的字符集還有比較規則優先。例如指定MySQL實例級別字符集是utf8mb4
,指定某個表字符集是latin1
,那么這個表的所有字段如果不指定的話,編碼就是latin1
由於字符集和比較規則是互相有聯系的,如果我們只修改了字符集,比較規則也會跟着變化,如果只修改了比較規則,字符集也會跟着變化,具體規則如下:
- 只修改字符集,則比較規則將變為修改后的字符集默認的比較規則。
- 只修改比較規則,則字符集將變為修改后的比較規則對應的字符集。
實例級別
通過兩個系統變量來指定實例級別的字符集與排序規則。
配置文件:
[server]
character_set_server=utf8mb4
collation_server=utf8mb4_general_ci
啟動之后,可以查看並修改這兩個變量。
mysql> show variables like 'character_set_server';
+----------------------+---------+
| Variable_name | Value |
+----------------------+---------+
| character_set_server | utf8mb4 |
+----------------------+---------+
1 row in set (0.06 sec)
mysql> show variables like 'collation_server';
+------------------+--------------------+
| Variable_name | Value |
+------------------+--------------------+
| collation_server | utf8mb4_general_ci |
+------------------+--------------------+
1 row in set (0.05 sec)
mysql> set character_set_server = 'utf8mb4';
Query OK, 0 rows affected (0.00 sec)
mysql> set collation_server = 'utf8mb4_general_ci';
Query OK, 0 rows affected (0.00 sec)
庫級別
創建數據庫的時候,可以指定字符集還有排序規則。
mysql> create database test_db character set utf8mb4 collate utf8mb4_general_ci;
Query OK, 1 row affected (0.01 sec)
不指定的話,就用實例級別的字符集還有排序規則。
查看當前數據庫的字符集還有排序規則則是通過use
命令指定數據庫之后,查看character_set_database
變量以及collation_database
來實現:
mysql> show variables like 'character_set_database';
+------------------------+---------+
| Variable_name | Value |
+------------------------+---------+
| character_set_database | utf8mb4 |
+------------------------+---------+
1 row in set (0.07 sec)
mysql> show variables like 'collation_database';
+--------------------+--------------------+
| Variable_name | Value |
+--------------------+--------------------+
| collation_database | utf8mb4_general_ci |
+--------------------+--------------------+
1 row in set (0.09 sec)
就算設置這兩個變量,也是無效的:
mysql> set character_set_database = 'utf8';
Query OK, 0 rows affected (0.00 sec)
mysql> show variables like 'character_set_database';
+------------------------+---------+
| Variable_name | Value |
+------------------------+---------+
| character_set_database | utf8mb4 |
+------------------------+---------+
1 row in set (0.09 sec)
修改數據庫的字符集還有排序規則的方式:
mysql> alter database test_db character set = 'utf8';
Query OK, 1 row affected (0.01 sec)
mysql> show variables like 'character_set_database';
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| character_set_database | utf8 |
+------------------------+-------+
1 row in set (0.08 sec)
這個更新只會對新建的表如果沒指定字符集和排序規則的生效,並不會更新老表的字符集還有排序規則。
表級別
可以在創建時指定字符集合排序規則,不指定的話,用數據庫的字符集還有排序規則,也可以修改字符集和排序規則。
mysql> create table test (name varchar(32)) character set utf8mb4 collate utf8mb4_bin;
Query OK, 0 rows affected (0.04 sec)
mysql> show create table test;
+-------+---------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+---------------------------------------------------------------------------------------------------------------------------------------+
| test | CREATE TABLE `test` (
`name` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin |
+-------+---------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.09 sec)
mysql> alter table test character set = 'utf8';
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show create table test;
+-------+--------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+--------------------------------------------------------------------------------------------------------------------------------------+
| test | CREATE TABLE `test` (
`name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+-------+--------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.06 sec)
可以看出,僅僅是表的字符集還有排序規則變了,對於已有字段,並沒有改變編碼和排序規則。
列級別
可以在創建表的時候,指定不同的列有不同的字符集和排序規則,也可以修改列的字符集和排序規則:
mysql> create table test (name varchar(32) character set utf8 collate utf8_bin) character set utf8mb4 collate utf8mb4_bin;
Query OK, 0 rows affected (0.03 sec)
mysql> show create table test;
+-------+-------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+-------------------------------------------------------------------------------------------------------------------------------------------------------+
| test | CREATE TABLE `test` (
`name` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin |
+-------+-------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.09 sec)
mysql> alter table test modify column name varchar(32) COLLATE latin1_bin;
Query OK, 0 rows affected (0.09 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show create table test;
+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+
| test | CREATE TABLE `test` (
`name` varchar(32) CHARACTER SET latin1 COLLATE latin1_bin DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin |
+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.09 sec)
MySQL客戶端字符編碼問題
有時候,我們會遇到字符編碼不一致導致的程序問題。例如我們的 Java 程序,使用 jdbc 鏈接。讀取的數據,打印出來是亂碼。或者是,MySQL 無法識別我們客戶端發來的命令。這涉及到字符編碼問題。我們需要保持 Java 程序的字符編碼與 JDBC 鏈接指定的字符編碼一致,這樣才不會有亂碼的問題。
指定 Java 程序編碼:通過啟動參數:-Dfile.encoding=UTF-8
設置默認的字符編碼(java.nio.charset.Charset.defaultCharset();
)是utf-8
(對應 MySQL 的utf8
還有utf8mb4
)。
指定 JDBC 鏈接編碼:
jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8
mysql客戶端命令行指定字符集
mysql -h 127.0.0.1 -P 3306 -u root --default-character-set=utf8mb4 -p
之后查看有關編碼的環境變量,都是和設置的這個字符集一樣。
mysql> SHOW VARIABLES LIKE 'character_set_client';
+----------------------+---------+
| Variable_name | Value |
+----------------------+---------+
| character_set_client | utf8mb4 |
+----------------------+---------+
1 row in set, 1 warning (0.00 sec)
mysql> SHOW VARIABLES LIKE 'character_set_connection';
+--------------------------+---------+
| Variable_name | Value |
+--------------------------+---------+
| character_set_connection | utf8mb4 |
+--------------------------+---------+
1 row in set, 1 warning (0.00 sec)
mysql> SHOW VARIABLES LIKE 'character_set_results';
+-----------------------+---------+
| Variable_name | Value |
+-----------------------+---------+
| character_set_results | utf8mb4 |
+-----------------------+---------+
1 row in set, 1 warning (0.00 sec)
其中:
character_set_client
: 服務器解碼請求時使用的字符集character_set_connection
:服務器處理請求時將字符集轉換成這個字符集處理。操作具體列時,在轉換為具體列的編碼。character_set_results
:服務器向客戶端返回數據時使用的字符集
MySQL 設計這三個編碼的時候,出於以下考慮:
- 一個 MySQL,可能有多種不同語言和操作系統或者國家的客戶端,所以通過設置
character_set_client
還有character_set_results
進行兼容。 - 由於操作具體列數據的時候需要編碼轉換,如果
character_set_connection
和字段一致的話,就不用轉換了,所以設置character_set_connection
可以讓 MySQL 用一種編碼理解命令統一處理,同時設置character_set_connection
為最常用的可以減少轉換。
一般情況下,保持這三個一致就好。我們就設置好連接使用的字符集就行了。
微信搜索“我的編程喵”關注公眾號,每日一刷,輕松提升技術,斬獲各種offer: