MySQL隱式數(shù)據(jù)轉(zhuǎn)換

引出

考慮如下問題:假設(shè)我們?cè)贛ySQL中存在表test,結(jié)構(gòu)如下:

CREATE TABLE `test` (
  `id` bigint(20),
  `name` varchar(20),
  PRIMARY KEY (`id`),
  KEY `ix_name` (`name`)
);

則我們寫出如下SQL:

select * from test where name = 123;
select * from test where id = '12';

問:此時(shí)這兩條SQL都會(huì)走索引嗎?
答:第一條不會(huì),第二條會(huì)。
原因:
第一條:MySQL的隱式數(shù)據(jù)轉(zhuǎn)換導(dǎo)致name會(huì)轉(zhuǎn)換為浮點(diǎn)數(shù)然后和123的浮點(diǎn)數(shù)比較,這句話的意思就是希望找到表中name轉(zhuǎn)換為浮點(diǎn)數(shù)后是123的行記錄。
所以整個(gè)過程就是遍歷test的每條記錄,依次進(jìn)行類型轉(zhuǎn)換后與123比較。顯然不走索引。
第二條:MySQL的隱式數(shù)據(jù)轉(zhuǎn)換導(dǎo)致'12'會(huì)轉(zhuǎn)換為數(shù)字12,這句話的意思就是:在表中想要找到id為數(shù)字12的行。
則上述語句和如下語句等同:

select * from test where id = 12;

所以顯然是走索引的。

MySQL隱式數(shù)據(jù)轉(zhuǎn)換

下面引入一段大家在很多地方都可以看到的話,即官方文檔的翻譯版:

MySQL 的隱式類型轉(zhuǎn)換原則:
1.  兩個(gè)參數(shù)至少有一個(gè)是 NULL 時(shí),比較的結(jié)果也是 NULL,例外是使用 <=> 對(duì)兩個(gè) NULL 做比較時(shí)會(huì)返回 1,這兩種情況都不需要做類型轉(zhuǎn)換
2.  兩個(gè)參數(shù)都是字符串,會(huì)按照字符串來比較,不做類型轉(zhuǎn)換
3.  兩個(gè)參數(shù)都是整數(shù),按照整數(shù)來比較,不做類型轉(zhuǎn)換
4.  十六進(jìn)制的值和非數(shù)字做比較時(shí),會(huì)被當(dāng)做二進(jìn)制串,和數(shù)字做比較時(shí)會(huì)按下面的規(guī)則處理
5.  有一個(gè)參數(shù)是 TIMESTAMP 或 DATETIME,并且另外一個(gè)參數(shù)是常量,常量會(huì)被轉(zhuǎn)換為 timestamp
6.  有一個(gè)參數(shù)是 decimal 類型,如果另外一個(gè)參數(shù)是 decimal 或者整數(shù),會(huì)將整數(shù)轉(zhuǎn)換為 decimal 后進(jìn)行比較,如果另外一個(gè)參數(shù)是浮點(diǎn)數(shù),則會(huì)把 decimal 轉(zhuǎn)換為浮點(diǎn)數(shù)進(jìn)行比較
7.  所有其他情況下,兩個(gè)參數(shù)都會(huì)被轉(zhuǎn)換為浮點(diǎn)數(shù)再進(jìn)行比較

注意一個(gè)安全問題:假如 password 類型為字符串,查詢條件為 int 0 則會(huì)匹配上。

其實(shí)這7條都很好理解。

說一下最后的注意問題:
  • 這句話的意思是任何不以數(shù)字開頭的字符串轉(zhuǎn)換為浮點(diǎn)數(shù)的時(shí)候,結(jié)果都是0。
    舉個(gè)??:


    image.png

    可以看到where name = 0居然將所有行查出來了。所以說如果password傳入的是數(shù)字0,且SQL又沒有類型檢測的話,密碼就可以這樣被破解了。

  • 上面的話沒有說完,如果以數(shù)字開頭呢?


    image.png

    可以看到這種轉(zhuǎn)換是取開頭的數(shù)字字符,如果沒有取到則直接輸出0。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容