前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MySQL 5.7&8.0开启sql_safe_updates安全模式的差异

MySQL 5.7&8.0开启sql_safe_updates安全模式的差异

作者头像
SEian.G
发布2021-07-07 15:07:43
1.7K0
发布2021-07-07 15:07:43
举报
文章被收录于专栏:SEian.G学习记录SEian.G学习记录

不知道大家是否有过维护的数据库表业务数据被人或者因为程序bug导致全表更新,全表删除的痛苦经历,恢复业务数据的过程真的太痛苦了,尤其与交易和钱相关的数据,必须恢复成和原来一模一样,那能不能在数据库层面架起最后一道安全堡垒,拒绝全表更新,全表删除的非法操作呢,答案是有的,在mysql中sql_safe_updates可以完美解决这个问题;

MySQL数据库是可以开启安全模式,不过默认情况下,安全模式不开启的,下面就来说说什么是mysql的安全模式,如下是sql_safe_updates参数的官方解释:

If this variable is enabled, UPDATE and DELETE statements that do not use a key in the WHERE clause or a LIMIT clause produce an error. This makes it possible to catch UPDATE and DELETE statements where keys are not used properly and that would probably change or delete a large number of rows. The default value is OFF.

sql_safe_updates默认是不开启的

代码语言:javascript
复制
mysql> show variables like 'sql_safe_updates';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| sql_safe_updates | OFF |
+------------------+-------+
1 row in set (0.01 sec)

现在就开启这个参数,如果要永久生效,需要将参数添加到数据库配置文件(my.cnf)中

代码语言:javascript
复制
mysql> set global sql_safe_updates=1;
Query OK, 0 rows affected (0.00 sec)

注意:需要重新连接一下数据库,才会生效;

下面就来给大家演示一下实际效果,以及在MySQL 5.7以及8.0版本在开启该参数之后进行更新和删除操作的差异;

代码语言:javascript
复制
mysql> CREATE TABLE `t_test1` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  `age` int DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_age` (`age`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
插入语句
insert into t_test1 values(NULL,'test1',21);
insert into t_test1 values(NULL,'test2',22);
insert into t_test1 values(NULL,'test3',23);
insert into t_test1 values(NULL,'test4',24);
insert into t_test1 values(NULL,'test5',25);
insert into t_test1 values(NULL,'test6',26);
insert into t_test1 values(NULL,'test7',27);
insert into t_test1 values(NULL,'test8',28);

测试一下全表删除

代码语言:javascript
复制
mysql> delete from t_test1;
ERROR 1175 (HY000): You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column.
 
mysql> delete from t_test1 where 1=1;
ERROR 1175 (HY000): You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column.

从上面的结果看,全部被数据库安全策略拦截了 再来测试一下更新

代码语言:javascript
复制
mysql> update t_test1 set name='test';
ERROR 1175 (HY000): You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column.
 
mysql> update t_test1 set name='test' where 1=1;
ERROR 1175 (HY000): You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column.

不带条件的更新也被拦截,那测试一下正常带条件的更新和删除看看效果

代码语言:javascript
复制
mysql> update t_test1 set name='test' where name='test1';
ERROR 1175 (HY000): You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column.
 
mysql> delete from t_test1 where name='test2';
ERROR 1175 (HY000): You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column.

为什么会这样呢,正常更新或者删除一条记录也会被mysql数据库安全策略拦截了呢?

下面针对update操作以及delete操作不同场景下的报错以及执行条件测试:

1、update操作

a、报错条件:不带where、带where无索引、where条件为常量 (1)不带where:update t_test1 set name=’test’; (2)带where无索引:update t_test1 set name=’test’ where name=’test1′; (3)where条件为常量:update t_test1 set name=’test’ where 1=1; b、执行条件:带where带索引、不带where+带limit、带where无索引+limit、带where有索引+limit、where条件为常量+limit (1)带where带索引:update t_test1 set name=’test’ where age=21; (2)不带where+带limit:update t_test1 set name=’test’ limit 1; (3)带where无索引+limit:update t_test1 set name=’test’ where name=’test1′ limit 1; (4)带where有索引+limit:update t_test1 set name=’test’ where age=21 limit 1; (5)where条件为常量+limit:update t_test1 set name=’test’ where 1=1 limit 1;

2、delete操作

相对于update,delelte的限制会更为严格;并且在5.7和8.0版本存在一点差异。

a、报错条件:不带where、带where无索引、不带where+带limit、where条件为常量、where条件为常量+limit 不带where:delete from t_test1; 带where无索引:delete from t_test1 where name=’test’; where条件为常量:delete from t_test1 where 1=1; b、执行条件:带where带索引、带where无索引+limit、带where有索引+limt 带where带索引:delete from t_test1 where age=22; 不带where+带limit:delete from t_test1 limit 1; (5.7版本执行会报错,8.0版本是可以执行成功的) 带where无索引+limit:delete from t_test1 where name=’test’ limit 1; 带where有索引+limit:delete from t_test1 where age=22 limit 1; where条件为常量+limit:delete from t_test1 where 1=1 limit 1;(5.7版本执行会报错,8.0版本是可以执行成功的)

大家重点关注上面粉色的条件(delete from t_test1 limit 1)和(delete from t_test1 where 1=1 limit 1;)这两种在5.7和8.0的执行情况是不一样的,在5.7版本,满足报错条件,会执行失败;而在8.0版本,满足执行调整,可以执行成功;


不知大家在使用MySQL Workbench操作数据库的时候是否注意到,Workbench默认是开启安全模式的,否则你的删除操作就会出现类型如下的报错信息:

从具体的报错信息中,也是可以看到原因以及解决方案:Edit–>Perferences–>SQL Editor

在实际通过workbench连接生产环境数据库的时候,是强烈不建议关闭的,避免人为导致全表删除或全表更新的操作;

总结

如果设置了sql_safe_updates=1,

update语句必须满足如下条件之一才能执行成功

1)使用where子句,并且where子句中列必须为索引列 2)使用limit 3)同时使用where子句和limit(此时where子句中列可以不是索引列)

delete语句,5.7和8.0版本有些差异,必须满足如下条件之一才能执行成功

5.7版本: 1)使用where子句,并且where子句中列必须为索引列 2)同时使用where子句和limit(此时where子句中列可以不是索引列) 8.0版本: 1)使用where子句,并且where子句中列必须为索引列 2)使用limit 3)同时使用where子句和limit(此时where子句中列可以不是索引列)

在生产环境中,建议开启该参数设置,这样不仅可以避免全表更新或删除的操作,也可以引导开发人员为where条件过滤的字段添加索引等;

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-06-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DBA的辛酸事儿 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 总结
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档