Navicat 博客

防止在存储过程中删除所有记录 2020 年 10 月 6 日,由 Robert Gravelle 撰写

允许某些用户对表执行临时更新或删除是相当普遍的。诸如此类的数据操作语言(Data Manipulation Language,DML)操作始终存在风险,如果有人沒有使用 WHERE 子句而意外发出 DELETE 命令,从而删除表中的所有行,则可能发生事故!幸运的是,你可以采取一些简单的步骤来防止意外(或故意!)破坏性的 DML 操作。我们将在今天的文章中研究其中的几个步骤。

危险删除过程

首先,让我们以一个存储过程为基础,该存储过程将根据用户提供的 WHERE 子句删除表中的行。Navicat for SQL Server 开发和管理客户端中显示的此 SQL Server 过程接受 tablewhereclause参数,并返回删除的行数:

delete_from_table_procedure (106K)

在 Navicat 中,我们可以通过“运行”按钮直接在编辑器中运行一个过程。点击它会弹出一个对话框以输入参数:

input_param_dialog (21K)

delcnt 指定了我们希望删除的记录数。若将其保留为空白,如果删除了任何行,则回滚事务并保留行。如果我们提供了一个数字,则该过程将在删除操作之后将其与 @@rowcount服务器变量进行比较,以确定删除的记录数是否与期望的数匹配。在我们的例子中,将显示一条消息,告诉我们would删除多少行:

would_have_been_deleted_message (30K)

如预期的那样,actcnt为零,确认实际上没有删除任何行:

actcnt_variable (20K)

delcnt 参数充当内置的故障保护,因为它强制用户指定他或她希望删除多少行。我们还可以通过检查是否提供了 whereclause 参数来添加一层额外的安全保护:

whereclause_check (17K)

最大化 delcnt 变量检查

禁止空的 WHERE 子句并非没有缺点,因为没有什么可以阻止用户输入“id not null”之类的东西。关于此安全检查,我们最多只能说至少只有在用户故意删除表中的所有行的情况下,检查才会失败。

因此,也许更好的解决方案可能是扩大将受影响(已删除)行的实际计数与预期计数(@delcnt)进行比较的想法。仅需几行代码,我们就可以计算表中的行数。如果受影响的行数等于表中的总行数,则回滚事务。这可以使用内置的 sp_executesql 存储过程来完成。它支持输入和输出参数的使用,因此我们可以将 count(*) 函数的结果存储到变量中。以下是新的代码:

delete_from_table_procedure_with_actcnt_check (148K)

现在,如果我们尝试运行一个查询,该查询将删除表中的所有行,如下所示:

input_param_dialog_with_destructive_whereclause_param (21K)

...删除被阻止:

actcnt_variable_check_validation_message (22K)

总结

虽然没有可靠的方法来防止由于意外或故意删除而造成的数据丢失,但是我们采用的每一种对策都有助于尽量减少发生灾难性事件的机会。

如果你对 Navicat for SQL Server 感兴趣,可以免费试用 14 天!

Navicat 文章
频道条目
分享
文章归档