MySQL-字符集

1、字符集和排序規則

1.一、簡介

1)MySQL提供了多種字符集和排序規則選擇,其中字符集設置和數據存儲以及客戶端與MySQL實例的交互相關,排序規則和字符串的對比規則相關html

2)字符集的設置能夠在MySQL實例、數據庫、表、列四個級別mysql

3)MySQL設置字符集支持在InnoDB, MyISAM, Memory三個存儲引擎web

4)查看當前MySQL支持的字符集的方式有兩種,一種是經過查看information_schema.character_sets系統表,一種是經過命令show character set查看算法

mysql> select * from information_schema.character_sets;

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

5)每一個指定的字符集都會有一個或多個支持的排序規則,能夠經過兩種方式查看,一種是查看information_schema.collations表,另外一種是經過show collation命令查看sql

  • 不一樣的字符集不可能有相同的排序規則
  • 每一個字符集都會有一個默認的排序規則
mysql> SHOW COLLATION WHERE Charset = 'latin1';
+-------------------+---------+----+---------+----------+---------+
| Collation         | Charset | Id | Default | Compiled | Sortlen |
+-------------------+---------+----+---------+----------+---------+
| latin1_german1_ci | latin1  |  5 |         | Yes      |       1 |
| latin1_swedish_ci | latin1  |  8 | Yes     | Yes      |       1 |
| latin1_danish_ci  | latin1  | 15 |         | Yes      |       1 |
| latin1_german2_ci | latin1  | 31 |         | Yes      |       2 |
| latin1_bin        | latin1  | 47 |         | Yes      |       1 |
| latin1_general_ci | latin1  | 48 |         | Yes      |       1 |
| latin1_general_cs | latin1  | 49 |         | Yes      |       1 |
| latin1_spanish_ci | latin1  | 94 |         | Yes      |       1 |
+-------------------+---------+----+---------+----------+---------+

image

6)每一個字符集能夠對應多個排序規則,但每一個排序規則只能對應一個字符集,例以下面的對應關係會報錯shell

mysql> SELECT _latin1 'x' COLLATE latin2_bin;
ERROR 1253 (42000): COLLATION 'latin2_bin' is not valid for CHARACTER SET 'latin1'

1.二、排序規則命名規則

1)排序規則的命令一般是以對應的字符集的名字爲開頭,並以本身的特定屬性結尾,好比排序規則utf8_general_ci和latin1_swedish_ci就分別是對應utf8和latin1字符集的排序規則數據庫

2)當排序規則特指某種語言時,則中間的部分就爲這種語言的名字,好比utf8_turkish_ci和utf8_hungarian_ci就表明UTF8字符集中的土耳其語和匈牙利語vim

3)排序規則名字的結尾字符表明是否大小寫敏感,重音敏感以及是不是二進制的瀏覽器

image

mysql> create table temp1(name varchar(10) charset latin1 collate latin1_general_ci,name2 varchar(10) charset latin1 collate latin1_general_cs);
mysql> insert into temp1 values('a','a'),('A','A');
mysql> select count(distinct name),count(distinct name2) from temp1;
+----------------------+-----------------------+
| count(distinct name) | count(distinct name2) |
+----------------------+-----------------------+
|                    1 |                     2 |
+----------------------+-----------------------+

4)當排序規則名字中沒有指定_as或者_ai時,則是否口音敏感是由_ci或者_cs決定,當使用的是_ci是則暗指_ai,反之則暗指_as。好比latin1_general_ci顯示指定大小寫不敏感,也暗指口音不敏感, 而latin1_general_cs顯示指定大小寫敏感,也暗指口音敏感bash

5)對Unicode的字符集來講,對應的排序規則也可能會包含unicode排序算法的版本號,若是沒有這個版本號顯示則表示是基於4.0.0這個版本,好比utf8_unicode_520_ci和utf8_unicode_ci

1.三、字符集和排序規則舉例

#默認狀況下的字符集是latin1
mysql> show variables like '%character%';
+--------------------------+----------------------------------+
| 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     | latin1                           |
| character_set_system     | utf8                             |
| character_sets_dir       | /usr/local/mysql/share/charsets/ |
+--------------------------+----------------------------------+

#在Latin1下建立的表默認字符集也是Latin1
mysql> create database chartest;

mysql> show create database chartest;
+----------+---------------------------------------------------------------------+
| Database | Create Database                                                     |
+----------+---------------------------------------------------------------------+
| chartest | CREATE DATABASE `chartest` /*!40100 DEFAULT CHARACTER SET latin1 */ |
+----------+---------------------------------------------------------------------+

mysql> create table temp(name varchar(100),name2 varchar(100));
mysql> show create table temp\G
*************************** 1. row ***************************
       Table: temp
Create Table: CREATE TABLE `temp` (
  `name` varchar(100) DEFAULT NULL,
  `name2` varchar(100) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1

1.四、ASCII碼

1)ASCII碼(American Standard Code for Information Interchange,美國信息交換標準代碼)是基於拉丁字母的一套電腦編碼系統。它主要用於顯示現代英語

2)ASCII的侷限在於只能顯示26個基本拉丁字母、阿拉伯數目字和英式標點符號,所以只能用於顯示現代美國英語(並且在處理英語當中的外來詞如naïve、café、élite等等時,全部重音符號都不得不去掉,即便這樣作會違反拼寫規則)

image

1.五、Latin字符集

1)Latin字符集:ISO 8859-1,正式編號爲ISO/IEC 8859-1:1998,又稱Latin-1或「西歐語言」,是國際標準化組織內ISO/IEC 8859的第一個8位字符集。它以ASCII爲基礎,在空置的0xA0-0xFF的範圍內,加入96個字母及符號,藉以供使用附加符號的拉丁字母語言使用

2)此字符集支持部分於歐洲使用的語言,包括阿爾巴尼亞語、巴斯克語、布列塔尼語、加泰羅尼亞語、丹麥語、荷蘭語、法羅語、弗裏西語、加利西亞語、德語、格陵蘭語、冰島語、愛爾蘭蓋爾語、意大利語、拉丁語、盧森堡語、挪威語、葡萄牙語、裏託羅曼斯語、蘇格蘭蓋爾語、西班牙語及瑞典語。

image

3)在latin字符集的表中插入英文和中文字符串

mysql> show variables like '%character%';
+--------------------------+----------------------------------+
| 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/ |
+--------------------------+----------------------------------+

CREATE TABLE `temp` (
`name` varchar(100) DEFAULT NULL,
`name2` varchar(100) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;


mysql> insert into temp values('china','中國');
mysql> select * from temp;
+-------+--------+
| name  | name2  |
+-------+--------+
| china | 中國   |  #能顯示中文
+-------+--------+

爲何latin字符集的表中能插入英文和中文字符串?

Latin1是一種很常見的字符集,這種字符集是單字節編碼,向下兼容ASCII,其編碼範圍是0x00-0xFF,0x00-0x7F之間徹底和ASCII一致,0x80-0x9F之間是控制字符,0xA0-0xFF之間是文字符號。很明顯,Latin1覆蓋了全部的單字節,所以,能夠將任意字符串保存在latin1字符集中,而不用擔憂有內容不符合latin1的編碼規範而被拋棄。——gbk和utf8是多字節編碼,沒有這種特性。
mysql使用者常常利用Latin1的這種全覆蓋特性,將其它類型的字符串,gbk,utf8,big5等,保存在latin1列中。保存的過程當中沒有數據丟失,只要原樣取出來,便又是合法的gbk/utf8/big字符串。若是將gbk字符串保存在utf8列中,則gbk字符串中那些不符合utf8編碼格式的內容,會被拋棄,保存的內容沒法原樣取出,數據實際上遭到了破壞

綜上,若是咱們看到一個字段的字符集是latin1的,那麼,他保存的多是任何編碼的字符串

所謂單字節編碼就是挨着一個個來,好比聖誕節到了,你要送妹子一箱蘋果,爲製造浪漫,商鋪提供兩種包裝方式,一是按個數來,即單個蘋果包裝進一個盒子,來一個包裝一個,這樣,妹子在拆完全部的盒子後完完整整的能夠還原爲一個個完整的和一箱無缺無損的蘋果,二是按重量來,每一個盒子限重2兩、3兩、6兩,這樣在包裝時,若恰好重3兩的固然能夠完整的放進一個盒子,可是若不夠或者多了,勉不了要切開蘋果,或者再往盒子中添加其餘的部分蘋果,這樣的話,妹子再不管怎樣拆開盒子,都會獲得一箱殘缺不堪的蘋果了,由於你在按照這種包裝方式進行時,已經破壞了單個蘋果的完整性,如今還原不回來了~咱們的字符集編碼轉換就是在作這種從新包裝的工做,latin1剛好就像單個蘋果包裝,而utf8就像第二種方式。

4)亂碼產生

亂碼方式一:能夠修復

mysql> select * from temp;  #自己時Latin1的字符編碼
+-------+--------+
| name  | name2  |
+-------+--------+
| china | 中國   |
+-------+--------+

mysql> set names utf8;  #客戶端設置爲utf8
mysql> show variables like '%character%';
+--------------------------+----------------------------------+
| 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/ |
+--------------------------+----------------------------------+
mysql> insert into temp values('china','中國');
ERROR 1366 (HY000): Incorrect string value: '\xE4\xB8\xAD\xE5\x9B\xBD' for column 'name2' at row 1

mysql> select * from temp; #以utf8字符編碼查看本來latin1會顯示亂碼,但能夠修復
+-------+---------------+
| name  | name2         |
+-------+---------------+
| china | 中国        |
+-------+---------------+

mysql> set names latin1;
mysql> select * from temp;
+-------+--------+
| name  | name2  |
+-------+--------+
| china | 中國   |
+-------+--------+

亂碼方式二:不能夠修復

1.六、實例級別字符集和排序規則

1)實例級別的字符集能夠在實例啓動的時候指定,默認的字符集是latin1,能夠經過--character-set-server參數指定實例的字符集,經過--collation-server參數指定實例的排序規則

[root@db01 ~]# cat /etc/my.cnf
[mysqld]
character-set-server = utf8

2)當僅指定了字符集沒有指定排序規則時,則默認的排序規則是該字符集的默認排序規則

3)如下三個啓動實例的方式的設置效果是同樣的:

shell> mysqld
shell> mysqld --character-set-server=latin1
shell> mysqld --character-set-server=latin1  --collation-server=latin1_swedish_ci

4)指定實例級別的字符集的做用是當create database語句中沒有指定字符集,則建立的數據庫默認是該字符集和排序規則

5)能夠經過MySQL系統變量查看實例的字符集和排序規則,變量名分別是character_set_server和collation_server

mysql> show variables like 'character_set_server';
+----------------------+--------+
| Variable_name        | Value  |
+----------------------+--------+
| character_set_server | latin1 |
+----------------------+--------+

mysql> show variables like 'collation_server';
+------------------+-------------------+
| Variable_name    | Value             |
+------------------+-------------------+
| collation_server | latin1_swedish_ci |
+------------------+-------------------+

6) Default-character-set是MySQL老版本中的「character_set_server」,在新版本中該參數改爲了character_set_server,若是在5.7版本中繼續使用老的參數會致使數據庫沒法啓動

[ERROR] unknown variable 'default-character-set=utf8'

1.七、數據庫級別字符集和排序規則

1)實例上的每一個數據庫都有一個字符集和排序規則,咱們能夠經過create database和alter database語句來指定和修改

image

2)數據庫的屬性值會存放在數據庫所在文件夾下的db.opt文件裏

[root@db01 course]# cat db.opt 
default-character-set=latin1
default-collation=latin1_swedish_ci

3)經過create/alter database語句裏指定字符集和排序規則,能夠建立不一樣於實例級別的字符集和排序規則,並且每一個數據庫均可以建立成不同

CREATE DATABASE db_name CHARACTER SET latin1 COLLATE latin1_swedish_ci;

4)當僅指定了字符集而沒有指定排序規則時,則會使用該字符集的默認排序規。當僅指定了排序規則而沒有字符集時,則在該排序規則名稱上含有的字符集會被使用

5)當數據庫建立時沒有指定這兩項,則使用實例級別的字符集和排序規則

6)alter database語句修改的字符集僅對數據庫中後續建立的表產生做用,不會修改已經建立表的字符集

1.八、表級別字符集和排序規則

1)每一個表都有本身的字符集和排序規則,能夠經過create table和alter table語句指定或修改表的字符集和排序規則

image

2)當建立和修改表時沒有指定排序規則時會使用字符集默認的排序規則。當建立和修改表時沒有指定字符集,則使用排序規則對應的字符集。當兩個屬性都沒有指定時,會使用數據庫級別的字符集和排序規則

3)alter table表的字符集不會改變已經存在的字段的字符集和字段裏的數據

1.九、列級別字符集和排序規則

1)每一個字符串字段(char, varchar, text)都有本身的字符集和排序規則,能夠經過create table和alter table指定和修改字段的字符集和排序規則

CREATE TABLE t1 ( col1 VARCHAR(5) CHARACTER SET latin1 COLLATE latin1_german1_ci );
ALTER TABLE t1 MODIFY col1 VARCHAR(5) CHARACTER SET latin1 COLLATE latin1_swedish_ci;

2)當字段上只指定了字符集時,排序規則會使用該字符集對應的默認排序規則當字段上只指定了排序規則時,則字符集會使用對應的字符集。當字段上二者都沒有定義時,則使用表級別的字符集和排序規則

CREATE TABLE t1 ( col1 CHAR(10) CHARACTER SET utf8 ) CHARACTER SET latin1 COLLATE latin1_bin;

3)經過alter table語句修改某一列的字符集時,MySQL會試圖轉換其中已有的數據,這樣的轉換有可能會致使數據丟失

mysql> create table temp2(name varchar(100));
mysql> insert into temp2 values('中國');
mysql> select * from temp2;
+--------+
| name   |
+--------+
| 中國   |
+--------+

mysql> alter table temp2 modify name varchar(100) character set greek; #不讓插了
ERROR 1366 (HY000): Incorrect string value: '\xE4\xB8\xAD\xE5\x9B\xBD' for column 'name' at row 1
mysql> alter table temp2 modify name varchar(100) character set utf8;
Query OK, 1 row affected (0.02 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> select * from temp2;
+--------+
| name   |
+--------+
| 中國   |
+--------+

1.十、字符串的字符集和排序規則

1)對於在SQL語句中出現的字符串,也會有本身的字符集和排序規則,一般是由character_set_connection和collation_connection兩個系統參數決定的

mysql> select @@character_set_connection;
+----------------------------+
| @@character_set_connection |
+----------------------------+
| latin1                     |
+----------------------------+

mysql> select @@collation_connection;
+------------------------+
| @@collation_connection |
+------------------------+
| latin1_swedish_ci      |
+------------------------+

2)也能夠顯示指定字符串的字符集和排序規則

[_charset_name]'string' [COLLATE collation_name]

SELECT 'abc';
SELECT _latin1'abc';
SELECT _binary'abc';
SELECT _utf8'abc' COLLATE utf8_danish_ci;

3)示例

mysql> select case when 'a'='A' then 1 else 0 end;
+-------------------------------------+
| case when 'a'='A' then 1 else 0 end |
+-------------------------------------+
|                                   1 |
+-------------------------------------+

mysql> set collation_connection=latin1_general_cs;
mysql> select case when 'a'='A' then 1 else 0 end;
+-------------------------------------+
| case when 'a'='A' then 1 else 0 end |
+-------------------------------------+
|                                   0 |
+-------------------------------------+

mysql> select case when 'a'=_latin1 'A' collate latin1_general_cs then 1 else 0 end;
+-----------------------------------------------------------------------+
| case when 'a'=_latin1 'A' collate latin1_general_cs then 1 else 0 end |
+-----------------------------------------------------------------------+
|                                                                     0 |
+-----------------------------------------------------------------------+

4)當charset和collation都指定時,使用這二者做爲字符串的字符集和排序規則

5)當僅指定charset時,則排序規則使用該字符集對應的默認排序規則

6)當僅指定排序規則時,則使用character_set_connection參數對應的字符集,且必須保證排序規則是字符集容許的

7)當二者都沒有指定時,則使用character_set_connection和collation_connection兩個參數指定的字符集和排序規則

8)好比SELECT _utf8'Müller';會使用utf8字符集和默認的utf8_general_ci排序規則。好比SELECT 'Müller' COLLATE utf8_general_ci;會使用系統鏈接的字符集,但若是字符集不是utf8就會報錯

mysql> set names latin1;
mysql> SELECT 'Müller' COLLATE utf8_general_ci;
ERROR 1253 (42000): COLLATION 'utf8_general_ci' is not valid for CHARACTER SET 'latin1'

1.十一、國家字符集

#標準SQL中會有兩種預約義的字符集數據類型,分別是nchar和nvarchar。 在MySQL中這種預約義的字符集就是UTF8,因此如下定義的最終結果是相同的:
CHAR(10) CHARACTER SET utf8
NATIONAL CHARACTER(10)
NCHAR(10)

#如下定義的最終結果也是相同:
VARCHAR(10) CHARACTER SET utf8
NATIONAL VARCHAR(10)
NVARCHAR(10)
NCHAR VARCHAR(10)
NATIONAL CHARACTER VARYING(10)
NATIONAL CHAR VARYING(10)

示例:

mysql> create table temp(name nchar(10),name2 nvarchar(10),name3 varchar(10));
mysql> show create table temp\G
*************************** 1. row ***************************
       Table: temp
Create Table: CREATE TABLE `temp` (
  `name` char(10) CHARACTER SET utf8 DEFAULT NULL,
  `name2` varchar(10) CHARACTER SET utf8 DEFAULT NULL,
  `name3` varchar(10) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1

對字符串來講,可使用N'字符串'的方式代表使用國家字符集,好比如下三種表達方式的結果是相同的:

SELECT N'some text';
SELECT n'some text';
SELECT _utf8'some text';

1.十二、其餘示例

#字段c1上的字符集和排序規則都已經顯示定義,因此會直接使用
CREATE TABLE t1 ( c1 CHAR(10) CHARACTER SET latin1 COLLATE latin1_german1_ci )
DEFAULT CHARACTER SET latin2 COLLATE latin2_bin;

#字段c1上僅定義了字符集沒有排序規則,則會使用latin1的默認排序規則,就是latin1_swedish_ci 而不是latin1_danish_ci
CREATE TABLE t1 ( c1 CHAR(10) CHARACTER SET latin1 ) DEFAULT CHARACTER SET latin1 COLLATE latin1_danish_ci;

#字段c1沒有定義字符集和排序規則,則會使用表級的字符集和排序規則
CREATE TABLE t1 ( c1 CHAR(10) ) DEFAULT CHARACTER SET latin1 COLLATE latin1_danish_ci;

#在字段和表級都沒有明確指定使用哪一種字符集和排序規則,則會沿用數據庫的字符集和排序規則
CREATE DATABASE d1 DEFAULT CHARACTER SET latin2 COLLATE latin2_czech_ci;
USE d1;
CREATE TABLE t1 ( c1 CHAR(10) );
-----------------------------------------------------------------------------

mysql> create table temp(name varchar(10) character set latin1 collate latin1_general_ci, name2 varchar(10) character set latin1 collate latin1_general_cs);
mysql> insert into temp values('a','a'),('A','A'),('b','b'),('B','B');
mysql> select * from temp order by name;
+------+-------+
| name | name2 |
+------+-------+
| a    | a     |
| A    | A     |
| b    | b     |
| B    | B     |
+------+-------+

mysql> select * from temp order by name2;
+------+-------+
| name | name2 |
+------+-------+
| A    | A     |
| a    | a     |
| B    | B     |
| b    | b     |
+------+-------+

1.1三、鏈接級字符集和排序規則

image

1)每一個數據庫客戶端鏈接都有本身的字符集和排序規則屬性,客戶端發送的語句的字符集是由character_set_client決定,而與服務端交互時會根據character_set_connection和collation_connection兩個參數將接收到的語句轉化。當涉及到顯示字符串的比較時,由collation_connection參數決定,而當比較的是字段裏的字符串時則根據字段自己的排序規則決定

2)character_set_result參數決定了語句的執行結果以什麼字符集返回給客戶端

3)客戶端能夠很方便的調整字符集和排序規則,好比使用SET NAMES 'charset_name' [COLLATE 'collation_name']代表後續的語句都以該字符集格式傳送給服務端,而執行結果也以此字符集格式返回

#好比一個set names語句至關於執行了如下三行語句:
SET character_set_client = charset_name;
SET character_set_results = charset_name;
SET character_set_connection = charset_nam;

#或者執行SET CHARACTER SET 'charset_name'命令,此命令和set names很是相似,惟一不一樣是將connection的字符集設置爲當前數據庫的字符集,因此至關於執行如下三行語句:
SET character_set_client = charset_name;
SET character_set_results = charset_name;
SET character_set_connection = @@character_set_database;

1.1四、應用程序配置字符集和排序規則

1)當應用程序使用MySQL默認的字符集和排序規則時,則應用程序端不須要特別的設置,而當不是使用默認屬性時則須要特別設置。好比咱們能夠靈活的的爲每個數據庫設置不一樣的字符集和排序規則,對應用程序來講就能夠經過set names命令與所操做的數據庫保持一致;在服務器端咱們能夠經過設置--character_set_server和--collation_server兩個參數來指定實例的默認字符集和排序規則,並將此做爲每一個數據庫和表的默認字符集和排序規則,好比

[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci

2)在應用程序端,也須要經過set names命令保證每一個數據庫連接和數據庫保持一致

3)咱們也能夠經過參數 --init_connect="SET NAMES 'utf8'" 來讓每一個客戶端鏈接都自動設置字符集,但缺點是對擁有super權限的用戶不生效init_connect表示服務器爲每一個鏈接的客戶端執行的字符串。字符串由一個或多個SQL語句組成。要想指定多個語句,用分號間隔開

SET GLOBAL init_connect='SET AUTOCOMMIT=0;set names utf8';

[mysqld]
init_connect='SET AUTOCOMMIT=0;set names utf8’

測試:

#編輯配置文件
[root@db01 ~]# vim /etc/my.cnf
[root@db01 ~]# cat /etc/my.cnf
[mysqld]
init_connect = 'SET AUTOCOMMIT=0;set names latin1'

#建立用戶
mysql> grant select on Course.* to cdq@'localhost' identified by 'cdq';

#用戶登陸測試
[root@db01 course]# mysql -ucdq -pcdq
mysql> show variables like '%character%';
+--------------------------+----------------------------------+
| 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/ |
+--------------------------+----------------------------------+

mysql> show variables like '%autocommit%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | OFF   |
+---------------+-------+

1.1五、排序規則在SQL中的使用

在SQL語句中指定排序規則能夠覆蓋以前定義的默認排序規則

#和order by語句使用
SELECT k FROM t1 ORDER BY k COLLATE latin1_german2_ci;

#和as語句使用
SELECT k COLLATE latin1_german2_ci AS k1 FROM t1 ORDER BY k1;

#和group by語句使用
SELECT k FROM t1 GROUP BY k COLLATE latin1_german2_ci;

#和聚合函數使用
SELECT MAX(k COLLATE latin1_german2_ci) FROM t1;

#和distinct一塊兒使用
SELECT DISTINCT k COLLATE latin1_german2_ci FROM t1;


mysql> select * from temp;
+------+-------+
| name | name2 |
+------+-------+
| a    | a     |
| A    | A     |
| b    | b     |
| B    | B     |

mysql> select count(distinct name2), count(distinct name2 collate latin1_general_ci) from temp;
+-----------------------+-------------------------------------------------+
| count(distinct name2) | count(distinct name2 collate latin1_general_ci) |
+-----------------------+-------------------------------------------------+
| 4                     |           2                                     |


#在where條件中使用
SELECT * FROM t1 WHERE _latin1 'Müller' COLLATE latin1_german2_ci = k;
SELECT * FROM t1 WHERE k LIKE _latin1 'Müller' COLLATE latin1_german2_ci;

#在having中使用
SELECT k FROM t1 GROUP BY k HAVING k = _latin1 'Müller' COLLATE latin1_german2_ci;

#在大部分的語句中,使用何種排序規則是明確的,好比以下幾個語句就是使用X列上的排序規則:
SELECT x FROM T ORDER BY x;
SELECT x FROM T WHERE x = x;
SELECT DISTINCT x FROM T;

#但也有複雜的狀況,好比當列和字符串都有各自的排序規則時:
SELECT x FROM T WHERE x = 'Y';
Concat(X,’Y’)

首先計算每種狀況的排序規則權重: 
1. 當有顯示的寫明優先級的,則權重爲0 
2. 當兩個有不一樣排序規則的字符串鏈接在一塊兒的,則權重爲1 
3. 字段和本地參數的排序規則,權重爲2 
4. 由部分字符串函數返回的系統常量所帶的排序規則,權重爲3 
5. 字符串自帶的排序規則,權重爲4 
...... 

在最終選擇使用哪一種排序規則上,規則爲: 
1. 優先使用權重最低的 
2. 若是二者擁有相同的優先級,則 
1)若是二者都是Unicode,或者都不是Unicode,則返回錯誤 
2)若是一邊是Unicode而另外一邊不是,則將不是Unicode的一邊轉化成Unicode字符集, 好比:SELECT CONCAT(utf8_column, latin1_column) FROM t1; latin1字符集的列會自動轉化爲utf8的字符集,再執行字符串鏈接 3)當兩邊都是相同字符集,且一邊是_bin而另外一邊是_ci/_cs的排序規則時,則使用_bin的排序規則

經過命令coercibility能夠查看權重,好比: 
mysql> SELECT COERCIBILITY('A' COLLATE latin1_swedish_ci); -> 0 
mysql> SELECT COERCIBILITY(VERSION()); -> 3 
mysql> SELECT COERCIBILITY('A'); -> 4 
mysql> SELECT COERCIBILITY(1000); -> 5

1.1六、Unicode字符集

1)Unicode(Universal Code)是一種在計算機上使用的字符編碼。Unicode 是爲了解決傳統的字符編碼方案的侷限而產生的,它爲每種語言中的每一個字符設定了統一而且惟一的二進制編碼,以知足跨語言、跨平臺進行文本轉換、處理的要求。Unicode存在不一樣的編碼方案,包括Utf-8,Utf-16和Utf-32。Utf表示Unicode Transformation Format。

  • Charset:字符集名字。
  • Description:對每一個字符集的簡短描述。
  • Default collation:每一個字符集的默認校對。
  • Maxlen:每一個字符集所保留的最大字節數。

2)MySQL支持的Unicode字符集包括如下幾種

image

3)BMP(BMP-Basic Multilingual Plane):基本多語言範圍 。若是將BMP以外的擴展字符轉換成utf8等僅支持BMP的字符集時,不識別的字符會轉化成?號 除UTF8外,客戶端字符集不支持設置爲其餘的Unicode字符集, 因此set names和set character set命令在Unicode要求下僅支持UTF8

4)UTF8(Unicode Transformation Format with 8-bit units)是一種存放Unicode數據的編碼規則。

  • 基礎拉丁字母,數字,標點符號會佔用一個字節
  • 擴展的拉丁字符,希臘語,斯拉夫語,阿拉伯語等會佔用兩個字節
  • 韓語,中文,日語字符會佔用3個或4個字節
  • 在MySQL中,UTF8字符集不支持擴展字符,且僅佔用最多3個字節
CREATE TABLE `temp1` ( `name` varchar(100) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 
mysql> insert into temp1 values(12),('ab'),('中國'),('a中'),('中a'); 
mysql> select name,length(name),char_length(name) from temp1;
+--------+--------------+-------------------+
| name   | length(name) | char_length(name) |
+--------+--------------+-------------------+
| 12     |            2 |                 2 |
| ab     |            2 |                 2 |
| 中國   |            6 |                 2 |
| a中    |            4 |                 2 |
| 中a    |            4 |                 2 |
+--------+--------------+-------------------+

1.1七、不一樣字符集下字符空間消耗

image

1)其中M在非二進制字段中表明定義的字符長度數值,L表明真實的字符所佔用的字節數

2)當定義varchar字段時,最大的長度爲65553個字節,且這個最大長度是整行數據共享的限制,當存儲好比Latin字符集時,每一個字節存儲一個字符,而當在多字節字符集好比UTF8時,因爲每一個字符最大要求3個字節的存儲,因此字段的最大建立長度就是21844個字

mysql> create table temp2(name varchar(21845)) charset=utf8;
ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs

2、MySQL字符集參數

2.一、查看當前數據庫字符集

mysql> show variables like 'character%';
+--------------------------+----------------------------------+
| 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/ |
+--------------------------+----------------------------------+

2.二、查看當前數據庫字符集校對

mysql> show variables like 'collation%';
+----------------------+-------------------+
| Variable_name        | Value             |
+----------------------+-------------------+
| collation_connection | utf8_general_ci   |
| collation_database   | latin1_swedish_ci |
| collation_server     | latin1_swedish_ci |
+----------------------+-------------------+

2.三、指定字符集方法

#在my.cnf或my.ini中指定
[mysqld]
character_set_server=utf8
	影響參數:character_set_server 和 character_set_database
	注意:修改後要重啓數據庫才能生效。
[client]
default-character-set=latin1
	影響參數:character_set_client,character_set_connection 和character_set_results。
	注意:修改後無需重啓數據庫。
	
mysql> show variables like '%character%';
+--------------------------+----------------------------------+
| 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/ |
+--------------------------+----------------------------------+

#在啓動參數前指定 
./mysqld --character-set-server=utf8 & 
影響參數:character_set_server 和 character_set_database 

#臨時指定 
mysql> SET character_set_client = utf8; 
mysql> SET character_set_connection = utf8; 
mysql> SET character_set_database = utf8; 
mysql> SET character_set_results = utf8; 
mysql> SET character_set_server = utf8; 

其中character_set_client,character_set_connection 和character_set_results,可經過一句話指定 
mysql> SET NAMES 'utf8';

3、MySQL字符集轉化過程

image

1)MySQL Server收到請求時將請求數據從character_set_client轉換爲character_set_connection;

2)進行內部操做前將請求數據從character_set_connection轉換爲內部操做字符集,其肯定方法以下:

  1. 使用每一個數據字段的CHARACTER SET設定值;
  2. 若上述值不存在,則使用對應數據表的DEFAULT CHARACTER SET設定值(MySQL擴展,非SQL標準);
  3. 若上述值不存在,則使用對應數據庫的DEFAULT CHARACTER SET設定值;
  4. 若上述值不存在,則使用character_set_server設定值(實例級別)。

3)將操做結果從內部操做字符集轉換爲character_set_results

4、MySQL字符集亂碼

4.一、產生亂碼緣由一:可恢復

1)客戶機沒有正確地設置client字符集,致使原先的SQL語句被轉換成connection所指字符集,而這種轉換,是會丟失信息的,若是client是utf8格式,那麼若是轉換成gb2312格式,這其中一定會丟失信息,反之則不會丟失。必定要保證connection的字符集大於client字符集才能保證轉換不丟失信息

2)數據庫字體沒有設置正確,若是數據庫字體設置不正確,那麼connection字符集轉換成database字符集照樣丟失編碼,緣由跟上面同樣。

3)好比向默認字符集爲utf8的數據表插⼊入utf8編碼的數據前鏈接字符集設置爲latin1,查詢時設置鏈接字符集爲utf8。插⼊入時根據MySQL服務器器的默認設置,character_set_client、character_set_connection和character_set_results均爲latin1;插⼊入操做的數據將通過latin1=>latin1=>utf8的字符集轉換過程,這過程當中每一個插⼊入的漢字都會從原始的3個字節變成6個字節保存;查詢時的結果將通過utf8=>utf8的字符集轉換過程,將保存的6個字節原封不不動返回,產⽣生亂碼

image

mysql> set names latin1;
mysql> show variables like '%character%';
+--------------------------+----------------------------------+
| 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/ |
+--------------------------+----------------------------------+

mysql> create table temp(name varchar(10)) charset utf8;
mysql> insert into temp values('中國');
mysql> select * from temp;
+--------+
| name   |
+--------+
| 中國 |
+--------+

mysql> set names utf8;
mysql> show variables like '%character%';
+--------------------------+----------------------------------+
| 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/ |
+--------------------------+----------------------------------+

mysql> select * from temp;
+---------------+
| name          |
+---------------+
| 中国 |
+---------------+

#存儲字符集編碼比插入時字符集大時,若是原封不動返回數據會出現亂碼,不過可經過修改查詢字符集,避免亂碼,即不會丟失數據
mysql> set names latin1;
mysql> select * from temp;
+--------+
| name   |
+--------+
| 中國 |
+--------+

4.二、產生亂碼緣由二:不可恢復

又好比向默認字符集爲latin1的數據表插入utf8編碼的數據前設置了鏈接字符集爲utf8,
插入時根據鏈接字符集設置,character_set_client、character_set_connection和character_set_results均爲utf8;
插入數據將通過utf8=>utf8=>latin1的字符集轉換,
若原始數據中含有\u0000~\u00ff範圍之外的Unicode字 符,會由於沒法在latin1字符集中表示而被轉換爲「?」(0×3F)符號,之後查詢時無論鏈接字符集設置
如何都沒法恢復其內容了

image

image

mysql> insert into temp values('中國');
ERROR 1366 (HY000): Incorrect string value: '\xE4\xB8\xAD\xE5\x9B\xBD' for column 'name' at row 1

4.三、亂碼解決方案

1)首先要明確你的客戶端是何種編碼格式,這是最重要的(IE6通常用utf8,命令行通常是gbk,通常程序是gb2312)

2)確保你的數據庫使用utf8格式,很簡單,全部編碼通吃。

3)必定要保證connection字符集大於等於client字符集,否則就會信息丟失,好比: latin1 < gb2312 < gbk < utf8,若設置set character_set_client = gb2312,那麼至少connection的字符集要大於等於gb2312,不然就會丟失信息

4)以上三步作正確的話,那麼全部中文都被正確地轉換成utf8格式存儲進了數據庫,爲了適應不一樣的瀏覽器,不一樣的客戶端,你能夠修改character_set_results來以不一樣的編碼顯示中文字體,因爲utf8是大方向,所以web應用仍是傾向於使用utf8格式顯示中文的。

相關文章
相關標籤/搜索