美文网首页
一条没有条件的UPDATE的分析

一条没有条件的UPDATE的分析

作者: 一根薯条 | 来源:发表于2019-10-30 22:09 被阅读0次

上周同事有条update SQL没有加条件就执行了,在DBA大佬的及时抢救下没有酿成事故。那条SQL比较有趣,简单分析一下。

分析过程

原表的结构:

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    |                |
+---------+------------------+------+-----+---------+----------------+

表中的数据:


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 |
+----+--------+---------+---------+

执行的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

更新的结果:

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语句如果需要更新多个字段,被更新的值需要用逗号分隔,而不是and。从更新结果看到,status字段全表被更新为1或者0,推断MySQL解析器把 and 连接的条件做了 与或运算 从而得到了bool值(true为1, false为0)。用sqlparser进行试验,结果成立。

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))
}

从结果中可以看到,status被设置为expr里面的值。

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

update语句中含有in条件,猜想 in 被解析成或运算执行的,观察这条被更新为1的结果和其原来的数据可以得出结论。

select * from update_test;
+----+--------+---------+---------+
| id | status | user_id | rule_id |
+----+--------+---------+---------+
|  1 |      2 |   10001 |       1 |  --- 原数据   更新条件为(status=2 && rule_id!= 100 && user_id=10001) 此记录均满足,猜想成立
+----+--------+---------+---------+
 
 
mysql> select * from update_test;
+----+--------+---------+---------+
| id | status | user_id | rule_id |
+----+--------+---------+---------+
|  1 |      1 |   10001 |       1 |  --- update之后的数据
+----+--------+---------+---------+

有的同学可能要说了,MySQL是有sql_safe_updates 配置的,默认关闭,只要打开,那么不加条件的update语句就无法执行,就不会出现这样的问题了,一劳永逸!

show variables like "sql_safe_updates";  -- 查看变量
set sql_safe_updates = 1;                -- session级别打开

这样其实是不行的,因为业务千奇百怪,有的场景需要不带条件的update, 而且如果开了,估计有的ORM就直接用不了了吧,到时候开发就该吐槽DBA了...

这是本人的想法,笔者又去问了一位资深数据库从业人员,那位大佬说的话非常有哲理,瞬间上升了一个维度:技术是用来保障服务的,而不是限制用户的,如果出现了全表更新,用flashback修复。

总结

想用人眼兜底所有的风险终究是不靠谱的。像这种有风险的操作应该走平台,让平台承担备份和提醒的工作~

相关文章

  • 一条没有条件的UPDATE的分析

    上周同事有条update SQL没有加条件就执行了,在DBA大佬的及时抢救下没有酿成事故。那条SQL比较有趣,简单...

  • SQL语句分别更新多条记录多个字段

    通常我们使用UPDATE语句更新记录,例如: 但有时我们需要在一条UPDATE语句中根据不同条件分别更新多条记录的...

  • 动态SQL 动态更新 set

    Set优化更新: 会成功拼接条件,最后一个”,”号会被去掉。 分析:所有字段修改:update t_blog se...

  • mongodb update

    db.集合名称.update({query},{update},upsert, multi})过滤条件;修改内容;...

  • MongoDB-更新

    提供了两类函数:save()、update()update函数语法要求比较麻烦:db.集合.update(更新条件...

  • MySQL Innodb死锁

    UPDATE MERGE INDEX DEADLOCK INNODB UPDATE的原理,行级锁的前提条件是建立索...

  • 不常见的sql

    不常见的sql 一条sql执行多个update 一条sql执行多个update CASE WHEN用法

  • mongodb更新文档

    update() 方法用于更新已存在的文档。语法格式如下: 参数说明:query : update的查询条件,类似...

  • MySQL安全模式

    MySQL安全模式要求不能对非主键的条件查询做update和delete操作报错: update activity...

  • SQL如何一次更新某列的多条数据

    update 表名 set 更新列的字段名='要更新的值' where 判断条件 例如: update custo...

网友评论

      本文标题:一条没有条件的UPDATE的分析

      本文链接:https://www.haomeiwen.com/subject/itgavctx.html