1、發現問題sql
一、在一次MySQL查詢中,某字段爲 varchar 字符串類型,傳入參數值爲 int 數字類型,發現查詢的結果和預期的不一致。 如: 某兩列 name='11' , name = '11aa' 。 where name = 11 , 能夠查到 '11' 和 '11aa' 兩個結果,這裏是錯誤的;而 where name ='11' ,能獲得預期結果。安全
二、反之,字段爲 int 數字類型,傳入參數值爲 varchar 字符串類型,也能查到數據,一樣查詢的結果和預期的不一致。如:age=2的數據有2條。where age = 2 , 能夠正常查到數據 ; 而 where age = '2aabbcc',查到的數據結果和 where age = 2 是同樣的,這裏是錯誤的,應該查不到數據。測試
2、代碼理解spa
一、針對【一】中的問題,描述的很差理解,晦澀難懂,下面用代碼加以理解,推進理解問題!3d
二、在MySQL數據中,建立一個 implicit 表 , 以下: (MySQL version 5.7+)code
SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- -- Table structure for implicit -- ---------------------------- DROP TABLE IF EXISTS `implicit`; CREATE TABLE `implicit` ( `id` varchar(255) NOT NULL COMMENT '編號', `name` varchar(255) DEFAULT NULL COMMENT '名稱', `age` int(11) DEFAULT NULL COMMENT '年齡', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='MySQL Implicit conversion (MySQL 隱式類型轉換)'; -- ---------------------------- -- Records of implicit -- ---------------------------- INSERT INTO `implicit` VALUES ('11', '小明', '2'); INSERT INTO `implicit` VALUES ('11qq', '小紅', '2'); INSERT INTO `implicit` VALUES ('12', '小新', '54'); INSERT INTO `implicit` VALUES ('tt11', '小剛', '92');
三、implicit 表數據以下:blog
3、針對問題進行測試ci
一、字段類型是 varchar 字符串,傳入參數爲 int 數字類型 。rem
1.一、-- 字段類型是 varchar ,傳入參數是 varchar 【預期正確結果】字符串
SELECT * FROM implicit a WHERE a.id = '11' ;
1.二、-- 字段類型是 varchar , 傳入參數是 int 【錯誤結果】
SELECT * FROM implicit a WHERE a.id = 11 ;
二、字段類型是 int 數字類型,傳入參數爲 varchar 字符串類型。
2.一、-- 字段類型是 int類型,傳入參數是 int類型 【預期正確結果】
SELECT * FROM implicit a WHERE a.age = 2 ;
2.二、-- 字段類型是 int類型,傳入參數是varchar類型 【錯誤結果】
SELECT * FROM implicit a WHERE a.age = '2aa' ;
4、問題緣由及避免
一、緣由: 當MySQL字段類型和傳入條件數據類型不一致時,會進行隱形的數據類型轉換(MySQL Implicit conversion)
二、若字符串是以數字開頭,且所有都是數字,則轉換爲數字結果是整個字符串;部分是數字,則轉換爲數字結果是截止到第一個不是數字的字符爲止。 理解: varchar str = "123dafa",轉換爲數字是123 。 SELECT '123dafa'+1 ; --- 124 。
三、若字符串不是以數字開頭,則轉換爲數字結果是 0 。 varchar str = "aabb33" ; 轉換爲數字是 0 。 SELECT 'aabb33'+100 ; --- 100 。
四、更多隱式轉換規則摘錄:
兩個參數至少有一個是 NULL 時,比較的結果也是 NULL,例外是使用 <=> 對兩個 NULL 作比較時會返回 1,這兩種狀況都不須要作類型轉換
兩個參數都是字符串,會按照字符串來比較,不作類型轉換
兩個參數都是整數,按照整數來比較,不作類型轉換
十六進制的值和非數字作比較時,會被當作二進制串
有一個參數是 TIMESTAMP 或 DATETIME,而且另一個參數是常量,常量會被轉換爲 timestamp
有一個參數是 decimal 類型,若是另一個參數是 decimal 或者整數,會將整數轉換爲 decimal 後進行比較,若是另一個參數是浮點數,則會把 decimal 轉換爲浮點數進行比較
全部其餘狀況下,兩個參數都會被轉換爲浮點數再進行比較。
5、問題總結
一、MySQL 隱式轉換問題,隱藏的深,不容易被發現,在進行 delete , update 等操做時,一不當心很容易大問題,從而形成事故。
二、對於 delete , update 等操做時,建議先使用 select 語句,看看獲取的結果和預期的是否一致,再進行操做,相對會更安全一些。
三、爲了便於更好理解,MySQL 隱式轉換規則,增長下面sql測試理解。
3.一、SELECT 'a10'+10 ; -- 10 SHOW WARNINGS ; -- WARNINGS: Truncated incorrect DOUBLE value: 'a10' 查看warnings能夠看到隱式轉化把字符串轉爲了double類型。可是由於字符串是非數字型的,因此就會被轉換爲0,所以最終計算的是0+10=10 . 3.二、SELECT '10a'+10 ; -- 20 SHOW WARNINGS ; -- WARNINGS: Truncated incorrect DOUBLE value: '10a' 3.三、SELECT 'a'=0 ; -- 1 , 至關於 true SHOW WARNINGS ; -- WARNINGS: Truncated incorrect DOUBLE value: 'a' 3.四、SELECT 'a23423' = 0 ; -- 1 , 至關於 true SHOW WARNINGS ; -- WARNINGS:Truncated incorrect DOUBLE value: 'a23423' 3.五、SELECT '11dafdfwwe'=11; -- 1, 至關於 true SHOW WARNINGS ; -- WARNINGS:Truncated incorrect DOUBLE value: '11dafdfwwe' 3.六、SELECT 11= 11 ; -- 1, 至關於 true SHOW WARNINGS ; -- 無 3.七、SELECT 'abc'='abc' ; -- 1, 至關於 true SHOW WARNINGS ; -- 無 3.八、SELECT 'abc'='abc232322' ; -- 0 , 數據類型同樣,不會進行轉換 SHOW WARNINGS ; -- 無 3.九、SELECT 'a'+'b'; -- 0 , 都轉換爲0了, 0+0=0 。 SHOW WARNINGS ; -- WARNINGS: Truncated incorrect DOUBLE value: 'a' , Truncated incorrect DOUBLE value: 'b' 3.十、SELECT 'a'+'b'='c' ; -- 1 ,等價於 0+0=0 --> 0=0=1。 SHOW WARNINGS ; -- WARNINGS: Truncated incorrect DOUBLE value: 'a' , Truncated incorrect DOUBLE value: 'b' , Truncated incorrect DOUBLE value: 'c'