1. 程式人生 > >MySQL不帶where條件的UPDATE和DELETE 限制操作說明

MySQL不帶where條件的UPDATE和DELETE 限制操作說明

據安全是業務的基石,但是DBA 總會遇到救火情況,業務誤刪除全表或者誤更新錯全表業務資料,導致服務不可用。

sql_safe_updates引數可以限制不帶where條件的update/delete語句執行失敗,這個引數設定後,可以防止業務bug/漏洞導致把整個表都更新或者刪除(線上發生過的案例),也可以防止DBA線上誤操作更新/刪除整張表。

官方解釋:

If set to 1, MySQL aborts UPDATE or DELETE statements that do not use a key in the WHERE clause or a LIMIT clause. (Specifically, UPDATE statements must have a WHERE clause that uses a key or a LIMIT clause, or both. DELETE statements must have both.) This makes it possible to catch UPDATE or DELETE statements where keys are not used properly and that would probably change or delete a large number of rows. The default value is 0.

意思是說

當sql_safe_updates設定為1時,UPDATE :要有where,並查詢條件必須使用為索引欄位,或者使用limit,或者兩個條件同時存在,才能正常執行。DELETE:where條件中帶有索引欄位可刪除,where中查詢條件不是索引,得必須有limit。主要是防止UPDATE和DELETE 沒有使用索引導致變更及刪除大量資料。系統引數預設值為0

為了防止線上業務出現以下3種情況影響線上服務的正常使用和不小心全表資料刪除:

1:沒有加where條件的全表更新操作

2:加了where 條件欄位,但是where 欄位 沒有走索引的表更新

3:全表delete 沒有加where 條件 或者where 條件沒有 走索引

如果業務開發存在如上的操作,資料庫會出現如下錯誤。 

MySQL 報錯如下:

 ERROR 1175 (HY000): You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column

DDB 報錯如下:

  1. Caused by: java.sql.SQLException: You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column
  2. at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:946)
  3. at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2985)
  4. at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1631)

建議: DBA 開啟此引數限制 ,可以避免線上業務資料誤刪除操作,但是需要先在測試庫開啟,這樣可以可以先在測試庫上補充短缺的表索引,測試驗證沒問題再部署到線上庫 郵件部從去年開始已經在嚴選電商線上執行。

測試案例: 全域性開啟 sql_safe_updates 限制

  1. [test]> show variables like 'sql_safe_updates';
  2. +------------------+-------+
  3. | Variable_name | Value |
  4. +------------------+-------+
  5. | sql_safe_updates | ON |
  6. +------------------+-------+
  1. CREATE TABLE `test_sql_safe` (
  2. `id` int(11) NOT NULL AUTO_INCREMENT,
  3. `uid` bigint(20) NOT NULL,
  4. `status` int(1) DEFAULT '0',
  5. `amount` int(11) NOT NULL DEFAULT '0',
  6. `nuid` bigint(20) NOT NULL,
  7. PRIMARY KEY (`id`),
  8. KEY `idx_uid` (`uid`)
  9. ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8
  1. [test]> select * from test_sql_safe;
  2. +----+------+--------+--------+--------+
  3. | id | uid | status | amount | nuid |
  4. +----+------+--------+--------+--------+
  5. | 1 | 1111 | 1 | 500 | 22222 |
  6. | 2 | 2111 | 0 | 600 | 332222 |
  7. | 3 | 3111 | 1 | 700 | 442222 |
  8. | 4 | 4111 | 0 | 500 | 552222 |
  9. | 5 | 5111 | 1 | 600 | 662222 |
  10. +----+------+--------+--------+--------+
  1. [test]> update test_sql_safe set amount = amount +100;
  2. ERROR 1175 (HY000): You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column
  1. test]> update test_sql_safe set amount = amount +100 limit 2;
  2. Query OK, 2 rows affected (0.00 sec)
  3. Rows matched: 2 Changed: 2 Warnings: 0
  1. [test]> select * from test_sql_safe ;
  2. +----+------+--------+--------+--------+
  3. | id | uid | status | amount | nuid |
  4. +----+------+--------+--------+--------+
  5. | 1 | 1111 | 1 | 600 | 22222 |
  6. | 2 | 2111 | 0 | 700 | 332222 |
  7. | 3 | 3111 | 1 | 700 | 442222 |
  8. | 4 | 4111 | 0 | 500 | 552222 |
  9. | 5 | 5111 | 1 | 600 | 662222 |
  10. +----+------+--------+--------+--------+
  1. [test]> update test_sql_safe set amount = amount +100 where uid = 2111;
  2. Query OK, 1 row affected (0.00 sec)
  3. Rows matched: 1 Changed: 1 Warnings: 0
  1. [test]> delete from test_sql_safe;
  2. ERROR 1175 (HY000): You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column
  1. delete from test_sql_safe where status = 0;
  2. ERROR 1175 (HY000): You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column
  1. delete from test_sql_safe where uid =3111;
  2. Query OK, 1 row affected (0.00 sec)
  1. [test]> delete from test_sql_safe where amount = 500 limit 1;
  2. Query OK, 1 row affected (0.00 sec)
  1. [test]> delete from test_sql_safe limit 1;
  2. ERROR 1175 (HY000): You are using safe update mode and you tried to update a table without a WHERE that uses a