日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

mysql字符集和校对规则(character sets and collations)详解

發布時間:2023/12/16 数据库 55 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mysql字符集和校对规则(character sets and collations)详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

mysql字符集(character sets)是指一系列符號以及符號對應的編碼的集合,比如英文字母可以用ASCII編碼,中文可以用GBK或者UTF8編碼。校對規則(collations)則是指一種比較字符的規則,這種比較規則決定了mysql如何進行排序以及如何對字符比較大小。

mysql的character sets和collations有很多種,而且可以在多個維度去配置,包含服務器的配置和客戶端的配置,對于初學者往往容易搞混,有時候出了亂碼等問題也不知道怎么排查。今天筆者就詳細梳理一下mysql中的character sets和collations。

我們先來看看mysql都可以配置哪些字符集,輸入如下命令查看。

show variables like '%character%';

?可以看到,有多達7個的character_set相關的參數,接下來我們就詳細說說這些參數。

查看mysql中支持的字符集和校對規則?

mysql中每個字符集都會對應多個校對規則,是一對多的關系。比如utf8對應的collation有utf8_general_ci,utf8_bin,utf8_unicode_ci等。而且每個character set會有個默認的collation與之對應,當我們在創建數據庫或者創建表時如果只指定character set,不指定collation,就會使用character set默認的collation。collation的命名是以對應的character set為開頭,比如collation為utf8_general_ci,我們就知道這個collation對應的字符集是utf8。

查看字符集

2種方式可以查看mysql中支持哪些字符集

1.?通過INFORMATION_SCHEMA.CHARACTER_SETS表來查看

2.?通過SHOW CHARACTER SET來查看,和上面表的結果是一樣的。

查看collations

通過 show collation?查看校對規則有哪些,還可在語句后面加where條件篩選。

配置與查看字符集與校對規則

服務器端相關character set和collation

mysql服務器端相關字符集是服務器對數據的存儲等相關的字符集,不涉及客戶端的問題。

mysql服務器端的字符集和校對規則可以在四個級別指定:server, database, table, column

server級別

在mysql5.7中,server character set 和 server collation 默認為 latin1 和 latin1_swedish_ci,在mysql8中,默認為utf8mb4 和 utf8mb4_0900_ai_ci

如果想要修改server級別的character set和collation,可以在啟動時指定參數

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

或者將上面的參數寫入到my.ini中[mysqld]下面,如下圖。

server級別的character set和collation的作用是為創建數據庫(CREAT DATABASE)時指定默認字符集和校對規則。也就是說創建數據庫時如果沒有指定character set和collation,就默認使用server級別的。

server級別的character set 和 collation可通過如下命令查看

show variables like 'character_set_server' show variables like 'collation_server'

?

database級別

數據庫級別的character set和collation可以在創建和修改數據庫時指定,如果不指定,則使用server級別的。

CREATE DATABASE db_name?[[DEFAULT] CHARACTER SET charset_name]?[[DEFAULT] COLLATE collation_name]ALTER DATABASE db_name?[[DEFAULT] CHARACTER SET charset_name]?[[DEFAULT] COLLATE collation_name]舉例:create database demo character set utf8 collate utf8_general_ci;

數據庫的character set和collation可通過INFORMATION_SCHEMA.SCHEMATA表查看。

比如下圖,我創建了三個數據庫test, test2, test3,test數據庫的character set和collation分別為utf8和utf8_general_ci,而test2和test3數據庫的character set和collation分別為latin1和latin1_swedish_ci。

也可以通過如下方式查看

USE db_name; SELECT @@character_set_database, @@collation_database;

數據庫級別的character set和collation會影響以下行為:

1.?創建表時,會默認使用database的character set和collation。

2.?使用mysql的LOAD DATA加載數據時,默認采用database的character set和collation。

3.?作用于存儲過程和函數,在創建存儲過程和函數時,傳遞的參數默認采用database的character set。

比如我的database?character set為latin1,然后我創建一個存儲過程proc1(nameStr varchar(20)),當我調用存儲過程call proc1('張三')時,會報錯,因為存儲過程proc1的參數只支持latin1字符集。

table級別

table的character set和collation可在創建表時指定,不指定默認采用database級別的。

CREATE TABLE tbl_name (column_list)[[DEFAULT] CHARACTER SET charset_name][COLLATE collation_name]]ALTER TABLE tbl_name[[DEFAULT] CHARACTER SET charset_name][COLLATE collation_name]

table級別的character set和collation會影響column級別的character set和collation,也就是column如果不指定character set和collation,就會默認繼承table級別的。

要想查看表的character set和collation,可通過information_schema.TABLES表查看,不過這個表只保存了collation信息,但是通過collation我們就能知道character set是什么了。

?或者通過如下命令查看

column級別

指定column級別的character set和collation,只有column的類型為字符型,如char,varchar,text等時,才可指定character set和collation。

col_name {CHAR | VARCHAR | TEXT} (col_length)[CHARACTER SET charset_name][COLLATE collation_name]舉例 CREATE TABLE t1 (col1 VARCHAR(5)CHARACTER SET latin1COLLATE latin1_german1_ci );ALTER TABLE t1 MODIFYcol1 VARCHAR(5)CHARACTER SET latin1COLLATE latin1_swedish_ci;

要查看列的character set和collation,可通過information_schema.COLUMNS表查看。

客戶端相關character set和collation

客戶端可能和mysql服務器采用不同的字符集,比如我們的java應用用的是一套字符集,mysql服務器用的是另一套字符集,這種情況下就要指定客戶端和服務器連接交互時的字符集。和客戶端相關的字符集配置有3個參數:character_set_client、character_set_connection、character_set_results。

這3個參數都是session級別的,也就是說不同的客戶端連接時可以把這3個參數指定為不同的值,而且在客戶端和服務器連接建立成功后,可以動態修改這3個值,不需要重啟mysql。

參數作用

mysql服務器把從客戶端接收的數據從character_set_client 轉成?character_set_connection,然后進行后續處理。把查詢結果轉成character_set_results返回給客戶端。所以character_set_client和character_set_connection是在向mysql發送命令的時候起作用,character_set_results是在接收mysql數據時起作用。

參數查看與設置

在連接mysql成功后,通過如下2種方式查看這三個參數的值。

方式一:

SELECT * FROM performance_schema.session_variables WHERE VARIABLE_NAME IN ( 'character_set_client', 'character_set_connection', 'character_set_results', 'collation_connection' ) ORDER BY VARIABLE_NAME;

方式二:

SHOW SESSION VARIABLES LIKE 'character\_set\_%'; SHOW SESSION VARIABLES LIKE 'collation\_%';

設置這三個參數的值有以下3種方式。

方式一:

在mysql客戶端連接時指定,可以配置在my.ini中,或者寫在命令行后面。

[mysql]

default-character-set=utf8

mysql -uroot -p?--default-character-set=utf8

方式二:

set names?charset_name?

這個命令等同于如下命令

SET character_set_client = charset_name;

SET character_set_results = charset_name;

SET?character_set_connection?=?charset_name;

方式三:

set character set charset_name,注意區分和set names的區別。這個命令會把character_set_connection設置為和database一樣,而不是指定的charset_name。

等于如下命令。

SET character_set_client = charset_name;

SET character_set_results = charset_name;

SET collation_connection = @@collation_database;

character_set_client、character_set_connection、character_set_results深入理解

一般我們把character_set_client、character_set_connection、character_set_results這三個值設置為一樣的比較好,這樣可以避免不必要的麻煩。但是具體這幾個參數怎樣在發揮作用,下面我們通過幾個例子來看一下。注意,下面的例子可能會比較容易把人繞暈,如果不感興趣,可以不看。上面講解的關于字符集和校對規則的知識應該可以應對日常開發了。

character_set_results參數作用示例

這里我們可以做個試驗加深理解,我們先試驗一下character_set_results。

我們建一個表,字符集設置為utf8,在表中插入一行數據。注意我這里插入數據是用的mysql 連接工具datagrip,沒有在cmd窗口中用mysql命令行,因為用命令行可能會影響后面的分析結果。

create table demo (id int auto_increment,name varchar(20) null,constraint demo_pkprimary key (id) ) character set utf8; insert into demo(name) value ('gitcat熊');

然后我們打開cmd窗口,連接mysql服務器。可以看到,連接好后,默認的character_set_client、character_set_connection、character_set_results都是gbk,這是因為windows系統默認的編碼是gbk。

然后我們查詢數據看看。可以看到中文可以正常顯示。這是因為mysql server端demo表的編碼是utf8,但是character_set_results配置的是gbk,所以mysql在返回數據之前把查出的數據轉成了gbk,又因為我們cmd窗口是以gbk編碼的,所以就正常顯示出了數據。?

我們把character_set_results設置成utf8再看看。可以看到顯示出問題了。因為我們告訴mysql server?character_set_results=utf8,所以mysql就會把查詢結果轉成utf8返回給我們,但是我們的cmd窗口是gbk編碼的,窗口會按照gbk解碼數據顯示,自然就顯示出問題了。?

我們可以驗證一下。熊的utf8編碼為E7868A,我們把這個編碼轉成gbk看看,因為gbk是兩個字節為單位編碼,所以我們先查詢一下gbk編碼E786對應的字是什么,從下圖可以看到正好是我們返回的select結果的第一個漢字“鐔”,然后再查一下8A,查不到可顯示的字符,因為GBK的編碼范圍是在8140-FEFE,所以返回結果顯示了個“□”。?

接下來我們把當前cmd窗口修改成用utf8編碼顯示,設置方式網上有很多,就是在cmd窗口執行一下命令 chcp 65001,會打開一個新的窗口,我們在新窗口重新連接mysql,可以看到,連接后的默認編碼已經變成utf8了。

這時我們再查詢一下,可以看到可以正常顯示。

這時如果我們把character_set_results設置成gbk,反而不能正常顯示了。因為我設置character_set_results=gbk,mysql server就會認為你要把查詢結果轉成gbk,mysql?server好心把結果給你轉成gbk了,結果你的窗口又以utf8解碼來顯示,當然就出問題了。 熊的gbk編碼是D0DC,Dü對應的unicode,正好也是D0和DC,印證了mysql服務器確實把熊這個字轉成gbk編碼傳給我們了。

細心的網友可能會發現,這里有個問題,就是為什么cmd窗口是以unicode解碼的,而不是utf8?因為我們返回的數據格式不符合utf8規則!

utf8編碼規則如下,可以看到,不是隨便給個2字節或者3字節的編碼,都能用utf8來解析出字符。所以猜測cmd窗口對于不能用utf8解析的編碼,只能以unicode來解碼了。如果我們返回的編碼正好是符合utf8規則的,那么cmd窗口就會以utf8正確解析出結果。

Unicode符號范圍 | UTF-8編碼方式 (十六進制) | (二進制) --------------------+--------------------------------------------- 0000 0000-0000 007F | 0xxxxxxx 0000 0080-0000 07FF | 110xxxxx 10xxxxxx 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 以漢字“嚴”為例,演示如何實現UTF-8編碼。 已知“嚴”的unicode是4E25(100111000100101), 根據上表,可以發現4E25處在第三行的范圍內(0000 0800-0000 FFFF), 因此“嚴”的UTF-8編碼需要三個字節,即格式是“1110xxxx 10xxxxxx 10xxxxxx”。 然后,從“嚴”的最后一個二進制位開始,依次從后向前填入格式中的x,多出的位補0。 這樣就得到了,“嚴”的UTF-8編碼是“11100100 10111000 10100101”,轉換成十六進制就是E4B8A5。

真的如我們猜測的這樣嗎?我們可以繼續做試驗來看。請接著往下看,下面會更精彩!

我們可以來做個實驗驗證上面我們的猜想。還是保持我們上面的實驗環境,即cmd窗口是utf8模式,設置character_set_results=gbk,然后我們在數據表demo中插入如下一條數據,注意我插入數據用的是datagrip,不是在當前cmd窗口,因為當前cmd窗口我們修改了一些參數,直接在這里插入會影響我們分析。

insert into demo(name) values('鍦ㄥ悧');

然后查詢一下結果。

?

很神奇,竟然沒有"亂碼",當然其實是亂碼了,因為和我們數據庫中存入的結果不一樣了。我們分析一下這里發生了什么。

首先mysql server從數據庫中查出"鍦ㄥ悧"這3個字,然后發現character_set_results=gbk,好吧,那mysql server就按照要求,把這3個字轉成gbk格式發送給客戶端,這3個字對應的gbk編碼是E59C(鍦)A8E5(ㄥ)9097(悧),現在cmd窗口接收到這個編碼了,要顯示在屏幕上了,因為cmd窗口設置的是utf8編碼,所以就以utf8方式來解析收到的編碼E59CA8E59097,而這一串編碼正好對應utf8中的"在嗎"。這也印證了我們之前的猜想,如果server傳回來的數據是符合utf8編碼規則的,cmd窗口就會以utf8規則幫我們解碼出數據顯示。

character_set_client、character_set_connection參數作用

接下來我們試驗一下character_set_client、character_set_connection這兩個參數的設置對數據的影響。前面說了,server把從客戶端接收的數據從character_set_client 轉成character_set_connection,比如我們發送了一條insert語句,mysql server就會以為,你發送的語句是用character_set_client編碼的,但是我要轉成character_set_connection,然后再執行插入語句。

我們還是先以默認方式連接mysql數據庫,如下。

然后在我們上面建的demo表里插入一條數據。可以看到,數據被正確地插入和讀出。因為我們當前窗口的編碼是gbk,而設置的character_set_client和character_set_connection也是gbk,所以mysql就會把我們的數據從gbk轉成gbk,再存入數據庫,當然就沒問題了。當然存入數據庫時發現表的編碼是utf8,所以其實這里又轉成utf8存入數據庫的,這一步和character_set_client和character_set_connection就沒關系了,我們先不深究。

接下來繼續試驗,這里只說一下結果,就不截圖了。

cmd窗口為gbk編碼時的情況

1. 如果cmd窗口是gbk編碼,character_set_client是gbk,character_set_connection是utf8,插入和查詢也沒問題。

2. 如果cmd窗口是gbk編碼,character_set_client是utf8,character_set_connection是utf8,插入無法插入,會報錯如下。

我們來分析一下這種情況,因為當前窗口是gbk編碼,所以傳給server的編碼是gbk的,但是因為character_set_client=utf8,server誤以為是utf8的,按照utf8來解碼,發現和utf8編碼規則不符合,所以報錯了。如果我們傳給server的gbk編碼正好也符合utf8編碼,server是不會報錯的,會插入成功,只是插入的數據不是我們預期的。比如下圖的例子,我們還是以“鍦ㄥ悧”這三個字舉例,如前所述,“鍦ㄥ悧”這三個字的gbk編碼是E59C(鍦)A8E5(ㄥ)9097(悧),而這個編碼正好也符合的utf8的編碼,server在拿到這個編碼后,按照utf8的規則解碼可以解碼成功,并且解碼出來是“在嗎”,于是就不會報錯了。

?

?3. 如果cmd窗口是gbk編碼,character_set_client是utf8,character_set_connection是gbk,這種情況可以插入數據,但是插入的數據不對。

?因為我們gbk編碼的熊字不能正確被解碼為utf8,所以在解碼為utf8時就已經亂碼了,后面所有的操作都會是亂碼的,所以數據是不對的。

cmd窗口為utf8編碼時的情況

1. 如果cmd窗口是utf8編碼,character_set_client和character_set_connection設置成utf8,毫無疑問,這種情況肯定是沒問題的,因為我們用的編碼都一樣。

2.?如果cmd窗口是utf8編碼,character_set_client=gbk和character_set_connection=utf8,結果如下,可以看到utf8編碼的熊為E7868A,E786正好對應gbk的"鐔",說明server是按照gbk解碼了utf8編碼的數據。

下面附一張在情況2這種情況下的另一個插入語句,有了前面我們的分析,你能明白結果為什么是這樣了嗎?

3.?如果cmd窗口是utf8編碼,character_set_client=gbk和character_set_connection=gbk,2次插入語句結果分別如下。

4.?如果cmd窗口是utf8編碼,character_set_client=utf8和character_set_connection=gbk,結果如下。

?情況3和情況4大家可以根據前面的分析自己分析一下結果,看看是否理解了。

總結

以上是生活随笔為你收集整理的mysql字符集和校对规则(character sets and collations)详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。