gpt4 book ai didi

sql-server - 我应该避免使用 sp_getAppLock 吗?

转载 作者:行者123 更新时间:2023-12-02 00:21:10 26 4
gpt4 key购买 nike

我有一个存储过程,我想确保它不能同时执行。

我的(多线程)应用程序通过此存储过程对基础表执行所有必要的工作。

IMO,锁定表本身是一个不必要的激烈操作,因此当我发现 sp_GetAppLock(它本质上强制执行关键部分)时,这听起来很理想。

我的计划是将存储过程封装在事务中,并使用事务范围设置 spGetAppLock。代码已编写并测试成功。

该代码现已提交审查,我被告知不应调用此函数。然而,当问“为什么不?”这个明显的问题时,我得到的唯一原因是非常主观的,与任何形式的锁定都很复杂有关。

我不一定买这个,但我想知道是否有人有任何客观理由为什么我应该避免这种构造。就像我说的,考虑到我的情况,关键部分对我来说听起来是一个理想的方法。

更多信息:在此之上有一个应用程序,具有 2 个线程 T1 和 T2。每个线程都在等待不同的消息 M1 和 M2。所涉及的业务逻辑表明,只有当 M1 和 M2 都到达时,才会进行处理。存储过程记录 Mx 已到达(插入),然后检查 My 是否存在(选择)。内置锁定可以很好地确保插入连续发生。但是选择也需要连续发生,我认为我需要在此处的内置功能之外做一些事情。

为了清楚起见,我希望“处理”只发生一次。所以我不能让存储过程返回误报或漏报。我担心如果存储过程连续快速运行两次,那么两个“选择”都可能返回表明适合执行处理的数据。

最佳答案

该过程在做什么,您不能依赖 SQL Server 内置的并发控制机制?通常可以重写查询以允许真正的并发。

但是,如果这个过程确实必须“单独”执行,那么在第一次访问时锁定表本身很可能比使用对 sp_GetAppLock 的调用要快得多。听起来这个过程会被经常调用。如果是这种情况,您应该寻找一种以最小的影响实现目标的方法。

<小时/>

如果表除了 M1 和 M2 之外不包含其他行,表锁仍然是您最好的选择。

如果您有多个线程发送多条消息,您可以通过使用“可序列化”作为事务级别来获得更细粒度,并在执行插入之前但在同一事务内检查其他消息是否存在。为了防止在这种情况下出现死锁,请确保检查两条消息,例如如下所示:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;  
BEGIN TRAN;
SELECT
@hasM1 = MAX(CASE WHEN msg_type='M1' THEN 1 ELSE 0 END),
@hasM2 = MAX(CASE WHEN msg_type='M2' THEN 1 ELSE 0 END)
FROM messages WITH(UPDLOCK)
WHERE msg_type IN ('M1','M2')

INSERT ...

IF(??) EXEC do_other_stuff_and_delete_messages;
COMMIT

在 COMMIT 之前(!)的 IF 语句中,您可以使用插入之前收集的信息以及插入的信息来决定是否需要进行其他处理。

在该处理步骤中,请确保将这些消息标记为已处理,或者将它们全部删除在同一事务中。这将确保您不会两次处理这些消息。

SERIALIZABLE 是唯一允许锁定尚不存在的行的事务隔离级别,因此带有 WITH(UPDLOCK) 的第一个 select 语句可有效防止在第一次执行时插入其他行仍在运行。

最后,有很多需要注意的事情可能会出错。您可能想看看服务代理。你可以使用三个队列。一种用于 M1 型,一种用于 M2 型。每次消息到达这些队列时,都会自动调用一个过程以将 token 插入到第三个队列中。然后,第三个队列可以激活一个进程来检查两条消息是否存在并且是否有效。这将使整个过程异步,但为此很容易限制队列 3 响应始终一次只执行一项检查。

msdn 上的服务代理,另请参阅自动消息处理的“激活”。

关于sql-server - 我应该避免使用 sp_getAppLock 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13070519/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com