【问题标题】:How do I limit a SQL stored procedure to be run by one person如何限制 SQL 存储过程由一个人运行
【发布时间】:2018-10-05 08:39:17
【问题描述】:

我有一个基本上从一个表插入到另一个表的存储过程。

当这个过程正在运行时,我不希望其他人能够启动它,但是我不希望序列化,其他人在我完成后运行该过程。

我想要的是让其他人在我运行程序时尝试启动它以得到错误。

我尝试过使用 sp_getapplock,但是我无法完全阻止此人运行该过程。

我还尝试使用 sys.dm_exec_requests 查找过程并阻止该过程,虽然这确实有效,但我认为这不是最佳选择,因为在某些服务器上我没有运行 sys.dm_exec_sql_text(sql_handle) 的权限。

对我来说最好的方法是什么?

【问题讨论】:

  • 首先出现在我脑海中的是。在过程开始时,创建一个用作锁的表。首先检查该表是否存在,如果不存在则创建一个。然后做剩下的事情并删除表。在此表中,您可以存储诸如谁在执行过程、在什么时间等信息。
  • 将 SET LOCK_TIMEOUT 设置为较低的值可能是解决方案的一部分,这意味着您在等待超过 x 毫秒后得到错误 1222。至于使用sp_getapplock时“无法完全阻止该人运行程序”,我无法评论。我们需要更多信息,或者最好是对此进行复制。
  • 你的意思是作为辅助空表吗?可以举个例子吗?
  • sp_getapplock 不就是为了停止并发吗?锁释放后,另一个执行该过程的人会自动启动它吗?

标签: sql sql-server stored-procedures


【解决方案1】:

狡猾的特技:

ALTER PROC MyProc
AS
BEGIN TRY
  IF OBJECT_ID('tembdb..##lock_proc_MyProc') IS NOT NULL
    RAISERROR('Not now.', 16, 0)
  ELSE
    EXEC('CREATE TABLE ##lock_proc_MyProc (dummy int)')
  ...

  EXEC('DROP TABLE ##lock_proc_MyProc')
END TRY
BEGIN CATCH
  ...    
  EXEC('DROP TABLE ##lock_proc_MyProc')
  ...
END CATCH
GO

可以通过存储 spid 和监视僵尸## 来扩展。

您也可以像TABLOCKUPDLOCK 一样提高隔离级别/粒度:

ALTER PROC MyProc
AS
BEGIN TRAN
  DECLARE @dummy INT
  SELECT @dummy=1
  FROM t (TABLOCKX, HOLDLOCK)
  WHERE 1=0

  ...
COMMIT TRAN

这将产生不同的效果 - 会等待,而不是跌倒。

【讨论】:

  • 动态 - 尽量减少因使用临时表而导致重新编译的机会。请注意,这个是##,而不是#。 @GordonLinoff
猜你喜欢
  • 1970-01-01
  • 2014-01-07
  • 1970-01-01
  • 2020-12-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多