最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

解決MySQL?Varchar?類型尾部空格的問題

 更新時(shí)間:2022年04月06日 14:30:57   作者:InfoQ  
這篇文章主要介紹了MySQL?Varchar?類型尾部空格,在這里需要注意的是?binary?排序規(guī)則的?pad?屬性為?NO?PAD,這里其實(shí)不是個(gè)例外,因?yàn)?char、varchar?和?text?類型都?xì)w類為?nonbinary,感興趣的朋友跟隨小編一起學(xué)習(xí)下吧

背景

近期發(fā)現(xiàn)系統(tǒng)中某個(gè)輸入框里如果輸入xxx+空格的時(shí)候會(huì)出現(xiàn)異常情況,經(jīng)過排查發(fā)現(xiàn)在調(diào)用后端接口時(shí)會(huì)有兩步操作,一是從數(shù)據(jù)庫中查詢到的數(shù)組中將與xxx+空格一致的元素剔除,二是根據(jù)xxx+空格從數(shù)據(jù)庫中查詢對(duì)應(yīng)的明細(xì)。

出現(xiàn)異常的原因是在剔除時(shí)未能剔除掉對(duì)應(yīng)的元素,也就意味著xxx+空格對(duì)應(yīng)的內(nèi)容在數(shù)據(jù)庫中不存在;但是在查詢明細(xì)時(shí)還是查詢到了,頓時(shí)感覺很費(fèi)解,也就衍生出了這篇文章后續(xù)的內(nèi)容。

原因

  • 開發(fā)人員在處理前端傳過來的字符串時(shí)沒有執(zhí)行 trim(),所以導(dǎo)致與數(shù)組中元素匹配的時(shí)候沒有匹配到,也就沒能剔除對(duì)應(yīng)的元素,"a".equals("a ") 的結(jié)果肯定是 false 嘛。

  • MySQL 在查詢時(shí)會(huì)忽略掉字符串最后的空格,所以導(dǎo)致xxx+空格作為查詢條件時(shí)和xxx為同一效果。

詳解

對(duì)于第一條原因只能說是開發(fā)時(shí)疏漏,沒什么可說的,我們著重了解下第二條,為什么 MySQL 會(huì)忽略掉查詢條件最后的空格。本文基于 MySQL 8.0.28,文章中有些內(nèi)容是 MySQL 8.0 新增的,但主體也適用于 5.x 版本。

在探究之前我們需要準(zhǔn)備下使用的數(shù)據(jù)庫,畢竟實(shí)踐出來的結(jié)果才是真實(shí)的,首先我們準(zhǔn)備一個(gè)測試使用的數(shù)據(jù)庫和表,結(jié)構(gòu)如下,字符集和排序規(guī)則先選擇比較常用的 utf8mb4 和 utf8mb4_unicode_ci,之后在表里插入兩條數(shù)據(jù):

mysql> desc test;
+--------------+-------------+------+-----+---------+-------+
| Field        | Type        | Null | Key | Default | Extra |
+--------------+-------------+------+-----+---------+-------+
| id           | int         | NO   | PRI | NULL    |       |
| name_char    | char(20)    | YES  |     | NULL    |       |
| name_varchar | varchar(20) | YES  |     | NULL    |       |
+--------------+-------------+------+-----+---------+-------+
3 rows in set (0.01 sec)
INSERT INTO `test` VALUES (1, 'char1', 'varchar1');
INSERT INTO `test` VALUES (2, 'char2     ', 'varchar2     ');

char 和 varchar 的區(qū)別

首先看一下官方對(duì)于 char 類型和 varchar 類型的介紹,以下內(nèi)容摘自【11.3.2 The CHAR and VARCHAR Types】

The length of a CHAR column is fixed to the length that you declare when you create the table. The length can be any value from 0 to 255. When CHAR values are stored, they are right-padded with spaces to the specified length. When CHAR values are retrieved, trailing spaces are removed unless the PAD_CHAR_TO_FULL_LENGTH SQL mode is enabled.
Values in VARCHAR columns are variable-length strings. The length can be specified as a value from 0 to 65,535. The effective maximum length of a VARCHAR is subject to the maximum row size (65,535 bytes, which is shared among all columns) and the character set used.

通過以上我們可以得知以下幾部分內(nèi)容:

  • char 類型長度為 0-255,varchar 類型長度為 0-65535,char 和 varchar 類型的長度其實(shí)還會(huì)受到內(nèi)容長度的影響,這里我們不深究。

  • char 類型為定長字段,存儲(chǔ)時(shí)會(huì)向右填充空格至聲明的長度;varchar 類型為變長字段,存儲(chǔ)時(shí)聲明的只是可存儲(chǔ)的最長內(nèi)容,實(shí)際長度與內(nèi)容有關(guān)。

  • 在 sql mode 中未開啟 PAD_CHAR_TO_FULL_LENGTH 時(shí),char 類型在查詢時(shí)會(huì)在忽略尾部空格(關(guān)于 sql mode 的資料請移步【5.1.11 Server SQL Modes】,這里我們不深究)

下面的查詢結(jié)果中第一行是都沒有空格的結(jié)果,第二行是都帶有 5 個(gè)空格的結(jié)果,可以看到 char 類型無論帶不帶空格都只會(huì)返回基本的字符。

mysql> select concat("(",name_char,")") name_char, concat("(",name_varchar,")") name_varchar from test;
+-----------+-----------------+
| name_char | name_varchar    |
+-----------+-----------------+
| (char1)   | (varchar1)      |
| (char2)   | (varchar2     ) |
+-----------+-----------------+
2 rows in set (0.01 sec)

第一行好理解,你存進(jìn)去的時(shí)候沒帶空格,數(shù)據(jù)庫自己填充上了空格,總不能查出來的結(jié)果還變了吧;第二行則是入庫的時(shí)候字符串最后的字符和數(shù)據(jù)庫填充的字符是同一種,查詢的時(shí)候數(shù)據(jù)庫怎么分得清是你自己填的還是它填的呢,直接一刀切。而 varchar 類型因?yàn)椴粫?huì)被填充,所以查詢結(jié)果中完成的保留下了尾部空格。

varchar 對(duì)于尾部空格的處理

上節(jié)了解過 char 類型查詢時(shí)會(huì)忽略尾部空格,但是在實(shí)際使用中發(fā)現(xiàn) varchar 也有類似的規(guī)則,在查看文檔時(shí)發(fā)現(xiàn)有以下一段內(nèi)容,摘自【11.3.2 The CHAR and VARCHAR Types】

Values in CHAR, VARCHAR, and TEXT columns are sorted and compared according to the character set collation assigned to the column.
MySQL collations have a pad attribute of PAD SPACE, other than Unicode collations based on UCA 9.0.0 and higher, which have a pad attribute of NO PAD.

根據(jù)這一段描述,我們可以得知 char、varchar 和 text 內(nèi)容的排序和比較過程受排序規(guī)則影響,在 UCA 9.0.0 之前 pad 屬性默認(rèn)為 PAD SPACE,而之后的默認(rèn)屬性為 NO PAD。

在官方文檔中可以找到以下說明,摘自【Trailing Space Handling in Comparisons】

For nonbinary strings (CHAR, VARCHAR, and TEXT values), the string collation pad attribute determines treatment in comparisons of trailing spaces at the end of strings:

  • For PAD SPACE collations, trailing spaces are insignificant in comparisons; strings are compared without regard to trailing spaces.

  • NO PAD collations treat trailing spaces as significant in comparisons, like any other character.

這一段主要描述 char、varchar 和 text 類型在比較時(shí),如果排序規(guī)則的 pad 屬性為 PAD SPACE 則會(huì)忽略尾部空格,NO PAD 屬性則不會(huì),而這正解釋了最初的問題。我們通過修改列的排序規(guī)則驗(yàn)證以下,首先看一下當(dāng)前使用 PAD SPACE 時(shí)的查詢結(jié)果。

mysql> show full columns from test;
+--------------+-------------+--------------------+------+-----+---------+-------+---------------------------------+---------+
| Field        | Type        | Collation          | Null | Key | Default | Extra | Privileges                      | Comment |
+--------------+-------------+--------------------+------+-----+---------+-------+---------------------------------+---------+
| id           | int         | NULL               | NO   | PRI | NULL    |       | select,insert,update,references |         |
| name_char    | char(20)    | utf8mb4_unicode_ci | YES  |     | NULL    |       | select,insert,update,references |         |
| name_varchar | varchar(20) | utf8mb4_unicode_ci | YES  |     | NULL    |       | select,insert,update,references |         |
+--------------+-------------+--------------------+------+-----+---------+-------+---------------------------------+---------+
3 rows in set (0.01 sec)

mysql> select * from test where name_varchar = 'varchar2';
+----+-----------+---------------+
| id | name_char | name_varchar  |
+----+-----------+---------------+
|  2 | char2     | varchar2      |
+----+-----------+---------------+
1 row in set (0.01 sec)

可以看到在 PAD SPACE 屬性下可以通過varchar2查詢到varchar2,說明比較時(shí)忽略的尾部的空格,我們將 name_varchar 的排序規(guī)則切換為 UCA 9.0.0 以后版本再來看一下結(jié)果。

mysql> ALTER TABLE test CHANGE name_varchar name_varchar VARCHAR(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
Query OK, 0 rows affected (0.05 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show full columns from test;
+--------------+-------------+--------------------+------+-----+---------+-------+---------------------------------+---------+
| Field        | Type        | Collation          | Null | Key | Default | Extra | Privileges                      | Comment |
+--------------+-------------+--------------------+------+-----+---------+-------+---------------------------------+---------+
| id           | int         | NULL               | NO   | PRI | NULL    |       | select,insert,update,references |         |
| name_char    | char(20)    | utf8mb4_unicode_ci | YES  |     | NULL    |       | select,insert,update,references |         |
| name_varchar | varchar(20) | utf8mb4_0900_ai_ci | YES  |     | NULL    |       | select,insert,update,references |         |
+--------------+-------------+--------------------+------+-----+---------+-------+---------------------------------+---------+
3 rows in set (0.01 sec)

mysql> select * from test where name_varchar = 'varchar2';
Empty set (0.00 sec)

與預(yù)期一樣,切換排序規(guī)則后,尾部空格參與比較,已經(jīng)不能通過varchar2查詢到varchar2了。

確定排序規(guī)則的 pad 屬性

那接下來的問題是如何判斷當(dāng)前的排序規(guī)則是基于 UCA 9.0.0 之前還是之后的版本呢?其實(shí)在 mysql 8.x 版本中,排序規(guī)則保存在 information_schema 庫的 COLLATIONS 表中,可以通過以下語句查詢對(duì)應(yīng)的 pad 屬性值,例如我們一開始選擇的 utf8mb4_unicode_ci。

mysql> select collation_name, pad_attribute from information_schema.collations where collation_name = 'utf8mb4_unicode_ci';
+--------------------+---------------+
| collation_name     | pad_attribute |
+--------------------+---------------+
| utf8mb4_unicode_ci | PAD SPACE     |
+--------------------+---------------+
1 row in set (0.00 sec)

除了查詢數(shù)據(jù)庫以外,還可以通過排序規(guī)則的名稱進(jìn)行區(qū)別,在官方文檔中有以下一段描述,摘自【Unicode Collation Algorithm (UCA) Versions】

MySQL implements the xxx_unicode_ci collations according to the Unicode Collation Algorithm (UCA) described at http://www.unicode.org/reports/tr10/. The collation uses the version-4.0.0 UCA weight keys: http://www.unicode.org/Public/UCA/4.0.0/allkeys-4.0.0.txt. The xxx_unicode_ci collations have only partial support for the Unicode Collation Algorithm.

Unicode collations based on UCA versions higher than 4.0.0 include the version in the collation name. Examples:

  • utf8mb4_unicode_520_ci is based on UCA 5.2.0 weight keys (http://www.unicode.org/Public/UCA/5.2.0/allkeys.txt),

  • utf8mb4_0900_ai_ci is based on UCA 9.0.0 weight keys (http://www.unicode.org/Public/UCA/9.0.0/allkeys.txt).

可以看出,名稱類似 xxx_unicode_ci 的排序規(guī)則是基于 UCA 4.0.0 的,而 xxx_520_ci 是基于 UCA 5.2.0,xxx_0900_ci 是基于 UCA 9.0.0 的。通過查詢數(shù)據(jù)庫驗(yàn)證,排序規(guī)則中包含 0900 字樣的 pad 屬性均為 NO PAD,符合以上描述。

需要注意的是 binary 排序規(guī)則的 pad 屬性為 NO PAD,這里其實(shí)不是個(gè)例外,因?yàn)?char、varchar 和 text 類型都?xì)w類為nonbinary。

到此這篇關(guān)于MySQLVarchar類型尾部空格的文章就介紹到這了,更多相關(guān)MySQLVarchar類型尾部空格內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Linux環(huán)境mysql5.7.12安裝教程

    Linux環(huán)境mysql5.7.12安裝教程

    這篇文章主要為大家詳細(xì)介紹了Linux環(huán)境Mysql5.7.12安裝教程,感興趣的小伙伴們可以參考一下
    2016-06-06
  • 淺談選擇mysql存儲(chǔ)引擎的標(biāo)準(zhǔn)

    淺談選擇mysql存儲(chǔ)引擎的標(biāo)準(zhǔn)

    本文介紹了如何選擇mysql存儲(chǔ)引擎,從存儲(chǔ)引擎的介紹、幾個(gè)常用引擎的特點(diǎn)三個(gè)方面進(jìn)行講解,感興趣的小伙伴們可以參考一下
    2015-07-07
  • MySQL數(shù)據(jù)庫給表添加索引的實(shí)現(xiàn)

    MySQL數(shù)據(jù)庫給表添加索引的實(shí)現(xiàn)

    在MySQL中,索引是用來加速數(shù)據(jù)庫查詢的一種特殊數(shù)據(jù)結(jié)構(gòu),當(dāng)我們需要查詢數(shù)據(jù)庫中某些數(shù)據(jù)的時(shí)候,如果數(shù)據(jù)庫中有索引,就可以避免全表掃描,從而提高查詢速度,本文就介紹了如何給表添加索引,感興趣的可以了解一下
    2023-08-08
  • 深入sql數(shù)據(jù)連接時(shí)的一些問題分析

    深入sql數(shù)據(jù)連接時(shí)的一些問題分析

    本篇文章是對(duì)關(guān)于sql數(shù)據(jù)連接時(shí)的一些問題進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-06-06
  • SQL窗口函數(shù)OVER用法實(shí)例整理

    SQL窗口函數(shù)OVER用法實(shí)例整理

    做SQL題時(shí)碰到了over()函數(shù)不太理解,所以整理了下,下面這篇文章主要給大家介紹了關(guān)于SQL窗口函數(shù)OVER用法的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-08-08
  • sqlite3遷移mysql可能遇到的問題集合

    sqlite3遷移mysql可能遇到的問題集合

    這篇文章主要給大家介紹了關(guān)于sqlite3遷移mysql可能遇到的問題集合,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • MySQL 5.7.22 二進(jìn)制包安裝及免安裝版Windows配置方法

    MySQL 5.7.22 二進(jìn)制包安裝及免安裝版Windows配置方法

    這篇文章通過實(shí)例代碼給大家介紹了MySQL 5.7.22 二進(jìn)制包安裝教程,文章末尾給大家補(bǔ)充介紹了mysql 5.7.22 免安裝版Windows配置方法,感興趣的朋友跟隨腳本之家小編一起看看吧
    2018-08-08
  • MySQL Range Columns分區(qū)的使用

    MySQL Range Columns分區(qū)的使用

    Range Columns分區(qū)是一種靈活的分區(qū)策略,允許基于列值的范圍將數(shù)據(jù)分到不同的分區(qū),本文主要介紹了MySQL Range Columns分區(qū)的使用,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-07-07
  • MySQL中的count(*)?和?count(1)?區(qū)別性能對(duì)比分析

    MySQL中的count(*)?和?count(1)?區(qū)別性能對(duì)比分析

    這篇文章主要介紹了MySQL中的count(*)和count(1)區(qū)別性能對(duì)比,本節(jié)還介紹了我們常說的索引下推,結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2023-05-05
  • MySQL進(jìn)階查詢、聚合查詢和聯(lián)合查詢

    MySQL進(jìn)階查詢、聚合查詢和聯(lián)合查詢

    這篇文章主要介紹了MySQL數(shù)據(jù)庫的進(jìn)階查詢,聚合查詢及聯(lián)合查詢,文中有詳細(xì)的代碼示例,需要的朋友可以參考閱讀
    2023-04-04

最新評(píng)論

锡林郭勒盟| 禄丰县| 汉阴县| 荔浦县| 乐东| 托克托县| 九龙县| 河间市| 紫云| 奈曼旗| 忻城县| 新乡县| 辉县市| 沭阳县| 台中县| 桂林市| 松原市| 喀什市| 新津县| 武义县| 磴口县| 大渡口区| 郧西县| 铁岭县| 晴隆县| 英德市| SHOW| 民乐县| 平远县| 兰坪| 伊川县| 皮山县| 浙江省| 定日县| 全南县| 普定县| 进贤县| 尼勒克县| 汝阳县| 罗甸县| 新竹县|