亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

MySQL的隱式類型轉(zhuǎn)換整理總結(jié)

 更新時間:2016年12月29日 08:28:46   作者:Rollen Holt  
隱式類型轉(zhuǎn)換有無法命中索引的風(fēng)險,在高并發(fā)、大數(shù)據(jù)量的情況下,命不中索引帶來的后果非常嚴(yán)重。下面這篇文章主要給大家整理總結(jié)了關(guān)于MySQL的隱式轉(zhuǎn)化,需要的朋友可以參考借鑒,下面來一起看看吧。

前言

前幾天在看到一篇文章:價值百萬的 MySQL 的隱式類型轉(zhuǎn)換感覺寫的很不錯,再加上自己之前也對MySQL的隱式轉(zhuǎn)化這邊并不是很清楚,所以就順勢整理了一下。希望對大家有所幫助。

當(dāng)我們對不同類型的值進行比較的時候,為了使得這些數(shù)值「可比較」(也可以稱為類型的兼容性),MySQL會做一些隱式轉(zhuǎn)化(Implicit type conversion)。

比如下面的例子:

mysql> SELECT 1+'1';
 -> 2
mysql> SELECT CONCAT(2,' test');
 -> '2 test'

很明顯,上面的SQL語句的執(zhí)行過程中就出現(xiàn)了隱式轉(zhuǎn)化。并且從結(jié)果們可以判斷出,第一條SQL中,將字符串的“1”轉(zhuǎn)換為數(shù)字1,而在第二條的SQL中,將數(shù)字2轉(zhuǎn)換為字符串“2”。

MySQL也提供了CAST()函數(shù)。我們可以使用它明確的把數(shù)值轉(zhuǎn)換為字符串。當(dāng)使用CONCA()函數(shù)的時候,也可能會出現(xiàn)隱式轉(zhuǎn)化,因為它希望的參數(shù)為字符串形式,但是如果我們傳遞的不是字符串呢:

mysql> SELECT 38.8, CAST(38.8 AS CHAR);
 -> 38.8, '38.8'
mysql> SELECT 38.8, CONCAT(38.8);
 -> 38.8, '38.8'

隱式轉(zhuǎn)化規(guī)則

官方文檔中關(guān)于隱式轉(zhuǎn)化的規(guī)則是如下描述的:

If one or both arguments are NULL, the result of the comparison is NULL, except for the NULL-safe <=> equality comparison operator. For NULL <=> NULL, the result is true. No conversion is needed.

  • If both arguments in a comparison operation are strings, they are compared as strings.
  • If both arguments are integers, they are compared as integers.
  • Hexadecimal values are treated as binary strings if not compared to a number.
  • If one of the arguments is a TIMESTAMP or DATETIME column and the other argument is a constant, the constant is converted to a timestamp before the comparison is performed. This is done to be more ODBC-friendly. Note that this is not done for the arguments to IN()! To be safe, always use complete datetime, date, or time strings when doing comparisons. For example, to achieve best results when using BETWEEN with date or time values, use CAST() to explicitly convert the values to the desired data type.
    A single-row subquery from a table or tables is not considered a constant. For example, if a subquery returns an integer to be compared to a DATETIME value, the comparison is done as two integers. The integer is not converted to a temporal value. To compare the operands as DATETIME values, use CAST() to explicitly convert the subquery value to DATETIME.
  • If one of the arguments is a decimal value, comparison depends on the other argument. The arguments are compared as decimal values if the other argument is a decimal or integer value, or as floating-point values if the other argument is a floating-point value.
  • In all other cases, the arguments are compared as floating-point (real) numbers.

翻譯為中文就是:

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

注意點

安全問題:假如 password 類型為字符串,查詢條件為 int 0 則會匹配上。

mysql> select * from test;
+----+-------+-----------+
| id | name | password |
+----+-------+-----------+
| 1 | test1 | password1 |
| 2 | test2 | password2 |
+----+-------+-----------+
2 rows in set (0.00 sec)

mysql> select * from test where name = 'test1' and password = 0;
+----+-------+-----------+
| id | name | password |
+----+-------+-----------+
| 1 | test1 | password1 |
+----+-------+-----------+
1 row in set, 1 warning (0.00 sec)

mysql> show warnings;
+---------+------+-----------------------------------------------+
| Level | Code | Message   |
+---------+------+-----------------------------------------------+
| Warning | 1292 | Truncated incorrect DOUBLE value: 'password1' |
+---------+------+-----------------------------------------------+
1 row in set (0.00 sec)

相信上面的例子,一些機靈的同學(xué)可以發(fā)現(xiàn)其實上面的例子也可以做sql注入。

假設(shè)網(wǎng)站的登錄那塊做的比較挫,使用下面的方式:

SELECT * FROM users WHERE username = '$_POST["username"]' AND password = '$_POST["password"]'

如果username輸入的是a' OR 1='1,那么password隨便輸入,這樣就生成了下面的查詢:

SELECT * FROM users WHERE username = 'a' OR 1='1' AND password = 'anyvalue'

就有可能登錄系統(tǒng)。其實如果攻擊者看過了這篇文章,那么就可以利用隱式轉(zhuǎn)化來進行登錄了。如下:

mysql> select * from test;
+----+-------+-----------+
| id | name | password |
+----+-------+-----------+
| 1 | test1 | password1 |
| 2 | test2 | password2 |
| 3 | aaa | aaaa |
| 4 | 55aaa | 55aaaa |
+----+-------+-----------+
4 rows in set (0.00 sec)

mysql> select * from test where name = 'a' + '55';
+----+-------+----------+
| id | name | password |
+----+-------+----------+
| 4 | 55aaa | 55aaaa |
+----+-------+----------+
1 row in set, 5 warnings (0.00 sec)

之所以出現(xiàn)上述的原因是因為:

mysql> select '55aaa' = 55;
+--------------+
| '55aaa' = 55 |
+--------------+
| 1 |
+--------------+
1 row in set, 1 warning (0.00 sec)

mysql> select 'a' + '55';
+------------+
| 'a' + '55' |
+------------+
| 55 |
+------------+
1 row in set, 1 warning (0.00 sec)

下面通過一些例子來復(fù)習(xí)一下上面的轉(zhuǎn)換規(guī)則:

mysql> select 1+1;
+-----+
| 1+1 |
+-----+
| 2 |
+-----+
1 row in set (0.00 sec)

mysql> select 'aa' + 1;
+----------+
| 'aa' + 1 |
+----------+
| 1 |
+----------+
1 row in set, 1 warning (0.00 sec)

mysql> show warnings;
+---------+------+----------------------------------------+
| Level | Code | Message  |
+---------+------+----------------------------------------+
| Warning | 1292 | Truncated incorrect DOUBLE value: 'aa' |
+---------+------+----------------------------------------+
1 row in set (0.00 sec)

把字符串“aa”和1進行求和,得到1,因為“aa”和數(shù)字1的類型不同,MySQL官方文檔告訴我們:

     When an operator is used with operands of different types, type conversion occurs to make the operands compatible.

查看warnings可以看到隱式轉(zhuǎn)化把字符串轉(zhuǎn)為了double類型。但是因為字符串是非數(shù)字型的,所以就會被轉(zhuǎn)換為0,因此最終計算的是0+1=1

上面的例子是類型不同,所以出現(xiàn)了隱式轉(zhuǎn)化,那么如果我們使用相同類型的值進行運算呢?

mysql> select 'a' + 'b';
+-----------+
| 'a' + 'b' |
+-----------+
|  0 |
+-----------+
1 row in set, 2 warnings (0.00 sec)

mysql> show warnings;
+---------+------+---------------------------------------+
| Level | Code | Message    |
+---------+------+---------------------------------------+
| Warning | 1292 | Truncated incorrect DOUBLE value: 'a' |
| Warning | 1292 | Truncated incorrect DOUBLE value: 'b' |
+---------+------+---------------------------------------+
2 rows in set (0.00 sec)

是不是有點郁悶?zāi)兀?/p>

之所以出現(xiàn)這種情況,是因為+為算術(shù)操作符arithmetic operator 這樣就可以解釋為什么a和b都轉(zhuǎn)換為double了。因為轉(zhuǎn)換之后其實就是:0+0=0了。

再看一個例子:

mysql> select 'a'+'b'='c';
+-------------+
| 'a'+'b'='c' |
+-------------+
|  1 |
+-------------+
1 row in set, 3 warnings (0.00 sec)

mysql> show warnings;
+---------+------+---------------------------------------+
| Level | Code | Message    |
+---------+------+---------------------------------------+
| Warning | 1292 | Truncated incorrect DOUBLE value: 'a' |
| Warning | 1292 | Truncated incorrect DOUBLE value: 'b' |
| Warning | 1292 | Truncated incorrect DOUBLE value: 'c' |
+---------+------+---------------------------------------+
3 rows in set (0.00 sec)

現(xiàn)在就看也很好的理解上面的例子了吧。a+b=c結(jié)果為1,1在MySQL中可以理解為TRUE,因為'a'+'b'的結(jié)果為0,c也會隱式轉(zhuǎn)化為0,因此比較其實是:0=0也就是true,也就是1.

第二個需要注意點就是防止多查詢或者刪除數(shù)據(jù)

mysql> select * from test;
+----+-------+-----------+
| id | name | password |
+----+-------+-----------+
| 1 | test1 | password1 |
| 2 | test2 | password2 |
| 3 | aaa | aaaa |
| 4 | 55aaa | 55aaaa |
| 5 | 1212 | aaa |
| 6 | 1212a | aaa |
+----+-------+-----------+
6 rows in set (0.00 sec)

mysql> select * from test where name = 1212;
+----+-------+----------+
| id | name | password |
+----+-------+----------+
| 5 | 1212 | aaa |
| 6 | 1212a | aaa |
+----+-------+----------+
2 rows in set, 5 warnings (0.00 sec)

mysql> select * from test where name = '1212';
+----+------+----------+
| id | name | password |
+----+------+----------+
| 5 | 1212 | aaa |
+----+------+----------+
1 row in set (0.00 sec)

​上面的例子本意是查詢id為5的那一條記錄,結(jié)果把id為6的那一條也查詢出來了。我想說明什么情況呢?有時候我們的數(shù)據(jù)庫表中的一些列是varchar類型,但是存儲的值為‘1123'這種的純數(shù)字的字符串值,一些同學(xué)寫sql的時候又不習(xí)慣加引號。這樣當(dāng)進行select,update或者delete的時候就可能會多操作一些數(shù)據(jù)。所以應(yīng)該加引號的地方別忘記了。

關(guān)于字符串轉(zhuǎn)數(shù)字的一些說明

mysql> select 'a' = 0;
+---------+
| 'a' = 0 |
+---------+
| 1 |
+---------+
1 row in set, 1 warning (0.00 sec)

mysql> select '1a' = 1;
+----------+
| '1a' = 1 |
+----------+
| 1 |
+----------+
1 row in set, 1 warning (0.00 sec)

mysql> select '1a1b' = 1;
+------------+
| '1a1b' = 1 |
+------------+
|  1 |
+------------+
1 row in set, 1 warning (0.00 sec)

mysql> select '1a2b3' = 1;
+-------------+
| '1a2b3' = 1 |
+-------------+
|  1 |
+-------------+
1 row in set, 1 warning (0.00 sec)

mysql> select 'a1b2c3' = 0;
+--------------+
| 'a1b2c3' = 0 |
+--------------+
|  1 |
+--------------+
1 row in set, 1 warning (0.00 sec)

從上面的例子可以看出,當(dāng)把字符串轉(zhuǎn)為數(shù)字的時候,其實是從左邊開始處理的。

  1. 如果字符串的第一個字符就是非數(shù)字的字符,那么轉(zhuǎn)換為數(shù)字就是0
  2. 如果字符串以數(shù)字開頭
  3. 如果字符串中都是數(shù)字,那么轉(zhuǎn)換為數(shù)字就是整個字符串對應(yīng)的數(shù)字
  4. 如果字符串中存在非數(shù)字,那么轉(zhuǎn)換為的數(shù)字就是開頭的那些數(shù)字對應(yīng)的值

總結(jié)

以上就是這篇文章的全部內(nèi)容了,如果你有其他更好的例子,或者被隱式轉(zhuǎn)化坑過的情況,歡迎分享。希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流。

相關(guān)文章

  • MySQL進階之索引

    MySQL進階之索引

    索引就是一種數(shù)據(jù)結(jié)構(gòu),這種結(jié)構(gòu)類似,鏈表,樹等等。但是比它們要復(fù)雜的多,索引(index)是幫助MySQL高效獲取數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)(有序),本文詳細介紹了MySQL索引,感興趣的同學(xué)可以參考閱讀
    2023-04-04
  • mysql 獲取當(dāng)前日期函數(shù)及時間格式化參數(shù)詳解

    mysql 獲取當(dāng)前日期函數(shù)及時間格式化參數(shù)詳解

    這篇文章主要介紹了mysql 獲取當(dāng)前日期函數(shù)now()及時間格式化DATE_FROMAT函數(shù)以及參數(shù)詳細介紹,需要的朋友可以參考下
    2014-08-08
  • MySQL通過函數(shù)存儲過程批量插入數(shù)據(jù)

    MySQL通過函數(shù)存儲過程批量插入數(shù)據(jù)

    這篇文章主要給大家介紹了關(guān)于MySQL通過函數(shù)存儲過程批量插入數(shù)據(jù),以及MySQL通過函數(shù)批量插入數(shù)據(jù)的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-01-01
  • RPM方式安裝MySQL5.6源碼

    RPM方式安裝MySQL5.6源碼

    這篇文章主要為大家分享了RPM方式安裝MySQL5.6源碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • mysql跨服務(wù)查詢之FEDERATED存儲引擎的實現(xiàn)

    mysql跨服務(wù)查詢之FEDERATED存儲引擎的實現(xiàn)

    本文主要介紹了mysql跨服務(wù)查詢之FEDERATED存儲引擎的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-01-01
  • mysql 5.7.16 ZIP包安裝配置教程

    mysql 5.7.16 ZIP包安裝配置教程

    這篇文章主要為大家詳細介紹了mysql 5.7.16 ZIP包安裝配置教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • 查看mysql語句運行時間的2種方法

    查看mysql語句運行時間的2種方法

    網(wǎng)站運行很慢的時候,我就特別起知道為什么這么慢,所以我查啊查,數(shù)據(jù)庫絕對是很重要的一部分,里面運行的sql是絕對不能放過的。平時做項目的時候,我也會注意sql語句的書寫,寫出一些高效的sql來,所以我會經(jīng)常測試自己寫的sql語句。我把我知道的二個方法,總結(jié)一下發(fā)出來
    2014-01-01
  • mysql 8.0.12 winx64下載安裝教程

    mysql 8.0.12 winx64下載安裝教程

    這篇文章主要為大家詳細介紹了mysql 8.0.12 winx64下載安裝教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-09-09
  • MySQL索引失效的原因及問題排查

    MySQL索引失效的原因及問題排查

    MySQL索引失效是指在查詢數(shù)據(jù)時,MySQL數(shù)據(jù)庫無法有效地使用索引來提高查詢性能,導(dǎo)致查詢速度變慢或者索引無效的情況,本文給大家介紹了MySQL中什么情況下會出現(xiàn)索引失效?以及如何排查索引失效?,需要的朋友可以參考下
    2024-04-04
  • mysql連接錯誤2013的問題及解決

    mysql連接錯誤2013的問題及解決

    這篇文章主要介紹了mysql連接錯誤2013的問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-05-05

最新評論