我有一个执行大量删除操作的存储过程。数十万条记录。它不能从应用程序中运行,但我仍然担心我的一个客户意外运行它(由于他们的“好奇心”,我早些时候遇到了问题):D
是的。有备份和类似的东西,但我在想......不要吓唬他们......有没有办法问用户“你确定吗?” 在执行之前?:) 谢谢
我有一个执行大量删除操作的存储过程。数十万条记录。它不能从应用程序中运行,但我仍然担心我的一个客户意外运行它(由于他们的“好奇心”,我早些时候遇到了问题):D
是的。有备份和类似的东西,但我在想......不要吓唬他们......有没有办法问用户“你确定吗?” 在执行之前?:) 谢谢
我猜你可能有一个名为“confirmation”的参数,它需要传入一个特定的字符串(例如,“我知道我在做什么”),如果它没有设置,或者设置不正确,只需从程序不执行主代码。不完全是您想要的,但它是一种选择。
例如 - (未经测试且可能很糟糕的语法)
CREATE PROCEDURE dbo.mySproc (
@Confirmation Varchar(100)
) AS
BEGIN
if(@Confirmation <> 'I know what I am doing')
BEGIN
return;
END
DELETE from table_name where condition
END
简而言之,没有。
该理论认为,任何有权查找并能够运行存储过程的人都应该被允许。最好限制权限,以便那些好奇的人没有权限运行它。
另一个不太安全的选项是需要一个需要作为参数传递的预定义秘密 - 当然,他们可以只编写存储过程的脚本以找到秘密......
当然,另一点是:如果它不可调用,为什么要包含它?毕竟,当您执行管理类型的任务时,您可以将语句脚本化为一个文件,您可以在自己的机器上保持安全
使用多层次的方法:
1)控制执行安全,如:
GRANT EXECUTE ON [dbo].[yourProcedure] TO [userxyz]
2) 使用真正描述性/可怕的过程名称,例如
CREATE PROCEDURE Will_Delete_All_Your_Data ...
3)在存储过程的开头放一个醒目的大注释
--NOTE, will delete all of your data--
--NOTE, will delete all of your data--
--NOTE, will delete all of your data--
--NOTE, will delete all of your data--
--NOTE, will delete all of your data--
4) 让用户传入一个经过混淆的特殊访问代码:
CREATE PROCEDURE Will_Delete_All_Your_Data
(
@SpecialCode varchar(30)
)
IF @SpecialCode!=CHAR(83)+CHAR(112)+CHAR(101)+CHAR(99)+CHAR(105)+CHAR(97)+CHAR(108)+CHAR(67)+CHAR(111)+CHAR(100)+CHAR(101)
BEGIN
RETURN 999
END
...
仅供参考,特殊代码必须是“SpecialCode”,否则会返回 999。
您可以@reallyReallyReallyDelete
向 sproc 添加一个参数作为安全措施:如果它设置为YesYesYes
将实际提交事务。
您可以使用调用的位输入@UserKnowsWhatTheyAreDoing
并在执行之前检查它是否为真。如果它是假的,打印一条友好的消息并从过程中优雅地返回
该过程可能需要具有特定值的参数,例如'Yes I know what I'm doing'
. 或者它可能会在具有类似确认和最近时间戳的特殊表中查找行。
这是另一种方法,我认为它适合用户直接调用过程而不是从应用程序调用的特定情况。
我必须说,与大多数其他建议相比,它给用户带来的麻烦更少,而给开发人员带来的麻烦更多(也许不成比例)。你决定它是否适合你。
不管怎样,就到这里吧。
首先,您创建一个特殊表 ,CriticalCalls
来注册对关键过程的调用。该表将具有如下结构:
SPID int,
ProcName sysname,
CallTime datetime
基本上,这个想法是一个关键的 SP 应该被调用两次:首先它注册它的调用并通知用户在一定的时间间隔内重复调用以确认他们的意图,如果相应地进行第二次调用,它实际上继续完成其任务。
所以每个关键过程的开始部分都会有这样的逻辑:
IF NOT EXISTS (
SELECT *
FROM CriticalCalls
WHERE SPID = @@SPID AND ProcName = @ThisProcName
AND GETDATE() - CallTime BETWEEN @LowerCallTimeLimit AND @UpperCallTimeLimit
/* the actual test for the time interval might be somewhat different */
) BEGIN
... /* upsert CriticalCalls with the current time stamp */
PRINT 'To proceed, please call this procedure again within...';
RETURN;
END;
DELETE FROM CriticalCalls WHERE SPID = @@SPID AND ProcName = @ThisProcName;
... /* proceed with your critical task */
实际上,我认为最好使用专用的 SP(CheckCriticalCalls
如下所示)进行所有操作CriticalCalls
,包括所有必要的修改。CheckCriticalCalls
将接收要检查的过程的名称并返回一种标志,显示指定的过程是否应该执行其实际操作。
所以它可能看起来像这样:
EXECUTE @result = CheckCriticalCalls 'ThisProcedureName';
IF @result = -1 BEGIN
PRINT 'Call me again';
RETURN;
END;
... /* go on with the task */
设置间隔下限背后的想法仅仅是为了防止用户自动调用两次关键过程,即EXECUTE...
在一批中执行两条相同的行。当然,上限对于 1) 确保用户确认他们最近执行关键操作的意图是必要的;2) 如果现有记录CriticalCalls
实际上是从具有相同 SPID 的过去会话中留下的,则阻止执行。
所以,基本上,1-2 秒到半分钟的间隔对我来说似乎很自然。您可能会选择不同的数字。
你真的需要从数据库中删除它们吗?如果我能负担得起额外的空间,我会在我的表格和最后更新的列中放置一个“已删除”标志。这样,如果一条记录被意外删除,至少我通常可以很容易地追踪它并恢复它。只是一个想法。