記一次字符串末尾空白丟失的排查 → MySQL 是會(huì)玩的!

2023-06-25 12:57:29 來(lái)源:博客園
開(kāi)心一刻

今天答應(yīng)準(zhǔn)時(shí)回家和老婆一起吃晚飯,但臨時(shí)有事加了會(huì)班,回家晚了點(diǎn)

回到家,本以為老婆會(huì)很生氣,但老婆卻立即從廚房端出了熱著的飯菜


(資料圖片僅供參考)

老婆:還沒(méi)吃飯吧,去洗下,來(lái)吃飯吧

我洗好,坐下吃飯,內(nèi)心感動(dòng)十分;老婆坐旁邊深情的看著我

老婆:你知道誰(shuí)最?lèi)?ài)你嗎

我毫不猶豫道:你

老婆:誰(shuí)最關(guān)心你?

我:你

老婆:我是誰(shuí)呀?

我:我老婆

老婆:那你以后是不是得對(duì)我好點(diǎn)?

這時(shí)電話響了,一看好哥們打過(guò)來(lái)的,我接了并開(kāi)了免提

哥們:樓下洗浴八折,干啥呢?

我:那個(gè)......,在陪我前妻吃口飯

問(wèn)題背景

一天,小伙伴找到我,他說(shuō)他碰到一個(gè)很奇怪的問(wèn)題

他說(shuō):明明表名的入?yún)⑹莟est ,為什么展示到界面的記錄包括test這條記錄?

他補(bǔ)充道:會(huì)不會(huì)是MyBatis-Plus做了什么騷操作,把test 末尾的空格給拿掉了

我:你直接把SQL語(yǔ)句到MySQL執(zhí)行下試試

結(jié)果如下:

這看起來(lái)不夠直觀,我移動(dòng)下光標(biāo)

然后我和小伙伴面面相覷

環(huán)境準(zhǔn)備

MySQL5、MySQL8各準(zhǔn)備一個(gè)

我們來(lái)看下默認(rèn)情況下,末尾空白的判斷情況

MySQL 5.7.36如下

1 表示TRUE,也就是相等

MySQL 8.0.27如下

0 表示FALSE,表示不相等

這是什么原因,我們繼續(xù)往下看

字符集與字符序

比較肯定就需要比較規(guī)則,SQL的比較規(guī)則就離不開(kāi)字符序,字符序又與字符集相關(guān),所以我們一個(gè)一個(gè)來(lái)捋

字符集

關(guān)于字符集,不是只言片語(yǔ)可以說(shuō)清楚的,但是大家也不用擔(dān)心,網(wǎng)上相關(guān)資料已經(jīng)非常多,大家擦亮慧眼去查閱即可

簡(jiǎn)單點(diǎn)來(lái)說(shuō):字符集定義了字符和字符的編碼

有人又問(wèn)了:字符、字符的編碼又是什么?

為了方便大家理解,舉個(gè)簡(jiǎn)單栗子

有四個(gè)字符:A、B、C、D,這四個(gè)字符的編碼分別是 A = 0, B = 1, C = 2, D = 3

這里的字符(A、B、C、D) + 編碼(0、1、2、3)就構(gòu)成了字符集(character set)

MySQL支持的字符集有很多,可以通過(guò)SHOW CHARACTER SET;查看

Charset:字符集名

Description:描述

Default collation:默認(rèn)字符序

Maxlen:每個(gè)字符最多字節(jié)數(shù)

字符序

定義了字符的比較規(guī)則;字符間的比較按何種規(guī)則進(jìn)行

一個(gè)字符集對(duì)應(yīng)多個(gè)字符序,通過(guò)SHOW COLLATION;可以查看全部的字符序;也可以帶條件查具體某個(gè)字符集的字符序

Default等于Yes表示是默認(rèn)字符序

每個(gè)字符集都有默認(rèn)的字符序

server的字符集與字符序

當(dāng)我們創(chuàng)建數(shù)據(jù)庫(kù)時(shí),沒(méi)有指定字符集、字符序,那么server字符集、server字符序就會(huì)作為該數(shù)據(jù)庫(kù)的字符集、字符序

database的字符集與字符序

指定數(shù)據(jù)庫(kù)級(jí)別的字符集、字符序

同一個(gè)MySQL服務(wù)下的數(shù)據(jù)庫(kù),可以分別指定不同的字符集、字符序

創(chuàng)建、修改數(shù)據(jù)庫(kù)的時(shí)候,可以通過(guò)CHARACTER SET、COLLATE指定數(shù)據(jù)庫(kù)的字符集、字符序

可以通過(guò)

查看數(shù)據(jù)庫(kù)的字符集和字符序

table的字符集與字符序

創(chuàng)建、修改表的時(shí)候,可以通過(guò)CHARACTER SET、COLLATE指定表的字符集、字符序

可以通過(guò)

查看表的字符序

column的字符集與字符序

類(lèi)型為CHAR、VARCHAR、TEXT的列,可以指定字符集、字符序

可以通過(guò)

查看字段的字符集和字符序

多個(gè)維度指定字符集、字符序的話,粒度越細(xì)的優(yōu)先級(jí)越高(column>table>database>server)

如果細(xì)粒度未指定字符集、字符序,那么會(huì)繼承上一級(jí)的字符集,字符序則是上一級(jí)字符集的默認(rèn)字符序

通常情況下我們一般不會(huì)指定table、column粒度的字符集、字符序

也就是說(shuō),通常情況下column的字符集會(huì)與database的字符集一致,而column的字符序則是database字符集的默認(rèn)字符序

空白丟失

上面講了那么多,跟空白丟失有什么關(guān)系?

大家先莫急,繼續(xù)往下看

MySQL5.7The CHAR and VARCHAR Types中有這么一段

翻譯過(guò)來(lái)就是:

1、類(lèi)型是CHAR、VARCHAR、TEXT列的值,會(huì)根據(jù)列的字符序來(lái)比較和排序

2、所有MySQL排序規(guī)則的類(lèi)型都是PAD SPACE。這就意味著,CHAR、VARCHAR、TEXT類(lèi)型的值進(jìn)行比較時(shí),不用考慮任何末尾空格,LIKE除外

3、不受SQL mode影響,也就是說(shuō)不管是嚴(yán)格模式,還是非嚴(yán)格模式,都不影響 2 所說(shuō)的規(guī)則

劃重點(diǎn),記筆記:在MySQL5.7及以下(<=5.7)版本中,排序規(guī)則都是PAD SPACE,末尾的空格會(huì)忽略不考慮

那如何讓末尾空格參與比較了,有三種處理方式

1、BINARY,類(lèi)似SELECT "test" = BINARY "test ";

2、LIKE,類(lèi)似SELECT "test" LIKE "test ";

3、LENGTH函數(shù),類(lèi)似

MySQL8做了調(diào)整,The CHAR and VARCHAR Types 有如下說(shuō)明

翻譯過(guò)來(lái)就是:

1、類(lèi)型是CHAR、VARCHAR、TEXT列的值,會(huì)根據(jù)列的字符序來(lái)比較和排序

2、MySQL字符序的pad參數(shù)的可選值,除了PAD SPACE,還增加了NO PAD

3、對(duì)于非二進(jìn)制字符串(CHAR、VARCHAR、TEXT),字符序pad參數(shù)決定如何去處理字符串末尾的空格

NO PAD不會(huì)忽略末尾空格,會(huì)將其當(dāng)做其他字符一樣對(duì)待

PAD SPACE會(huì)忽略末尾空格,LIKE除外

SQL mode不參與字符串末尾空格的處理

MySQL8server 維度的字符集是utf8mb4,對(duì)應(yīng)的默認(rèn)字符序是:utf8mb4_0900_ai_ci

Pad_attribute的值是NO PAD,也就是不會(huì)忽略字符串末尾的空格

所以在MySQL8中,SELECT "test" = "test ";默認(rèn)情況下得到的結(jié)果是 0

總結(jié)

1、非二進(jìn)制字符串(CHAR、VARCHAR、TEXT)比較時(shí),末尾空格的處理跟列的字符序有直接關(guān)系

2、MySQL5.7及之前的版本,排序規(guī)則的類(lèi)型都是PAD SPACE,會(huì)忽略字符串末尾的空格,LIKE除外

3、MySQL8開(kāi)始,字符序增加了一個(gè)參數(shù)Pad_attribute,該參數(shù)的值不同,對(duì)字符串末尾空格的處理方式不同

NO PAD:字符串末尾的空格會(huì)和其他字符一樣,不會(huì)被忽略

PAD SPACE:字符串末尾的空格會(huì)被忽略,LIKE除外

4、如上針對(duì)的都是非二進(jìn)制字符串的排序和比較,而不是儲(chǔ)存

參考

The CHAR and VARCHAR Types

The CHAR and VARCHAR Types

再見(jiàn)亂碼:5分鐘讀懂MySQL字符集設(shè)置

關(guān)鍵詞: