一條沒有條件的UPDATE的分析

上周同事有條update SQL沒有加條件就執(zhí)行了,在DBA大佬的及時(shí)搶救下沒有釀成事故。那條SQL比較有趣,簡(jiǎn)單分析一下。

分析過(guò)程

原表的結(jié)構(gòu):

desc update_test;
+---------+------------------+------+-----+---------+----------------+
| Field   | Type             | Null | Key | Default | Extra          |
+---------+------------------+------+-----+---------+----------------+
| id      | int(11) unsigned | NO   | PRI | NULL    | auto_increment |
| status  | int(11)          | NO   |     | NULL    |                |
| user_id | bigint(20)       | NO   |     | NULL    |                |
| rule_id | tinyint(4)       | NO   |     | NULL    |                |
+---------+------------------+------+-----+---------+----------------+

表中的數(shù)據(jù):


select * from update_test;
+----+--------+---------+---------+
| id | status | user_id | rule_id |
+----+--------+---------+---------+
|  1 |      2 |   10001 |       1 |
|  2 |      1 |   10002 |     100 |
|  3 |      3 |   10003 |     100 |
|  4 |      4 |   10004 |     100 |
|  5 |      1 |   10005 |     100 |
|  6 |      2 |   10006 |       2 |
|  7 |      3 |   10007 |     100 |
|  8 |      2 |   10008 |       1 |
|  9 |      4 |   10009 |     100 |
| 10 |      1 |   10010 |       1 |
+----+--------+---------+---------+

執(zhí)行的update SQL:

update
    update_test
set
    status = 10
    and status in (2, 3)
    and rule_id != 100
    and user_id in (
        10001,
        10002,
        10003,
        10004,
        10005
);
Query OK, 10 rows affected (0.01 sec)
Rows matched: 10  Changed: 10  Warnings: 0

更新的結(jié)果:

mysql> select * from update_test;
+----+--------+---------+---------+
| id | status | user_id | rule_id |
+----+--------+---------+---------+
|  1 |      1 |   10001 |       1 |
|  2 |      0 |   10002 |     100 |
|  3 |      0 |   10003 |     100 |
|  4 |      0 |   10004 |     100 |
|  5 |      0 |   10005 |     100 |
|  6 |      0 |   10006 |       2 |
|  7 |      0 |   10007 |     100 |
|  8 |      0 |   10008 |       1 |
|  9 |      0 |   10009 |     100 |
| 10 |      0 |   10010 |       1 |
+----+--------+---------+---------+
10 rows in set (0.01 sec)

update語(yǔ)句如果需要更新多個(gè)字段,被更新的值需要用逗號(hào)分隔,而不是and。從更新結(jié)果看到,status字段全表被更新為1或者0,推斷MySQL解析器把 and 連接的條件做了 與或運(yùn)算 從而得到了bool值(true為1, false為0)。用sqlparser進(jìn)行試驗(yàn),結(jié)果成立。

package main

import (
    "fmt"
    "github.com/xwb1989/sqlparser"
)

func main() {
    sql := `update update_test set status = 10 and rule_id != 100 and role_id in (2,3);`
    stmt, _ := sqlparser.Parse(sql)

    //fmt.Printf("%#v\n", stmt)
    u := stmt.(*sqlparser.Update)
    fmt.Println("field: ", u.Exprs[0].Name.Name, "\nexpr :", sqlparser.String(u.Exprs[0].Expr))
}

從結(jié)果中可以看到,status被設(shè)置為expr里面的值。

field:  status 
expr : 10 and rule_id != 100 and role_id in (2, 3)

update語(yǔ)句中含有in條件,猜想 in 被解析成或運(yùn)算執(zhí)行的,觀察這條被更新為1的結(jié)果和其原來(lái)的數(shù)據(jù)可以得出結(jié)論。

select * from update_test;
+----+--------+---------+---------+
| id | status | user_id | rule_id |
+----+--------+---------+---------+
|  1 |      2 |   10001 |       1 |  --- 原數(shù)據(jù)   更新條件為(status=2 && rule_id!= 100 && user_id=10001) 此記錄均滿足,猜想成立
+----+--------+---------+---------+
 
 
mysql> select * from update_test;
+----+--------+---------+---------+
| id | status | user_id | rule_id |
+----+--------+---------+---------+
|  1 |      1 |   10001 |       1 |  --- update之后的數(shù)據(jù)
+----+--------+---------+---------+

有的同學(xué)可能要說(shuō)了,MySQL是有sql_safe_updates 配置的,默認(rèn)關(guān)閉,只要打開,那么不加條件的update語(yǔ)句就無(wú)法執(zhí)行,就不會(huì)出現(xiàn)這樣的問題了,一勞永逸!

show variables like "sql_safe_updates";  -- 查看變量
set sql_safe_updates = 1;                -- session級(jí)別打開

這樣其實(shí)是不行的,因?yàn)闃I(yè)務(wù)千奇百怪,有的場(chǎng)景需要不帶條件的update, 而且如果開了,估計(jì)有的ORM就直接用不了了吧,到時(shí)候開發(fā)就該吐槽DBA了...

這是本人的想法,筆者又去問了一位資深數(shù)據(jù)庫(kù)從業(yè)人員,那位大佬說(shuō)的話非常有哲理,瞬間上升了一個(gè)維度:技術(shù)是用來(lái)保障服務(wù)的,而不是限制用戶的,如果出現(xiàn)了全表更新,用flashback修復(fù)。

總結(jié)

想用人眼兜底所有的風(fēng)險(xiǎn)終究是不靠譜的。像這種有風(fēng)險(xiǎn)的操作應(yīng)該走平臺(tái),讓平臺(tái)承擔(dān)備份和提醒的工作~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • ORA-00001: 違反唯一約束條件 (.) 錯(cuò)誤說(shuō)明:當(dāng)在唯一索引所對(duì)應(yīng)的列上鍵入重復(fù)值時(shí),會(huì)觸發(fā)此異常。 O...
    我想起個(gè)好名字閱讀 6,020評(píng)論 0 9
  • ORACLE自學(xué)教程 --create tabletestone ( id number, --序號(hào)usernam...
    落葉寂聊閱讀 1,255評(píng)論 0 0
  • 1. 簡(jiǎn)介 1.1 什么是 MyBatis ? MyBatis 是支持定制化 SQL、存儲(chǔ)過(guò)程以及高級(jí)映射的優(yōu)秀的...
    笨鳥慢飛閱讀 6,280評(píng)論 0 4
  • 什么是數(shù)據(jù)庫(kù)? 數(shù)據(jù)庫(kù)是存儲(chǔ)數(shù)據(jù)的集合的單獨(dú)的應(yīng)用程序。每個(gè)數(shù)據(jù)庫(kù)具有一個(gè)或多個(gè)不同的API,用于創(chuàng)建,訪問,管理...
    chen_000閱讀 4,148評(píng)論 0 19
  • 1.首先下載相關(guān)jar包和dll:https://sourceforge.net/projects/jacob-p...
    尋找大海的魚閱讀 1,792評(píng)論 0 0

友情鏈接更多精彩內(nèi)容