我的(多线程)应用程序通过此存储过程在底层表上执行所有必要的工作.
imo,锁定表本身是一个不必要的激烈的行动,所以当我发现关于sp_GetAppLock,这实质上强制一个关键部分,这听起来是理想的.
我的计划是将存储过程封装在事务中,并设置具有事务范围的spGetAppLock.代码已经成功编写和测试.
该代码现已提交审查,我被告知我不应该调用这个功能.然而,当提出明确的问题“为什么不呢?”时,我得到的唯一原因是非常主观的,与任何形式的锁定是复杂的.
我不一定会买这个,但我想知道是否有任何客观的理由,为什么我应该避免这个建筑物.就像我说的,鉴于我的情况,一个关键的部分听起来是一个理想的方法.
TIA,
皮特
进一步的信息:应用程序位于此顶部与2线程T1和T2.每个线程正在等待不同的消息M1和M2.所涉及的业务逻辑表明,只有M1和M2都到来,处理才能发生.存储过程记录Mx到达(插入),然后检查是否存在My(选择).内置的锁定是很好的,以确保插入顺序发生.但是选择也需要顺序发生,我想我需要在内置功能上做一些.
为了清楚起见,我想要“处理”发生一次.所以我买不起存储过程来返回假阳性或假阴性.我担心如果存储过程连续快速运行两次,那么“选择”可能会返回指示执行处理的数据.
解决方法
但是,如果这个过程确实必须单独执行,那么在第一次访问时锁定表本身就比使用对sp_GetAppLock的调用要快很多.听起来这个程序会经常被叫做.如果是这种情况,您应该寻找一种以最小影响实现目标的方法.
如果该表除M1和M2之外没有其他行,则表锁仍然是您最好的选择.
如果您有多个线程发送多个消息,您可以通过使用“serializable”作为事务级别获得更细致的粒子,并在执行插入之前检查其他消息是否在同一个事务中.为了防止在这种情况下的死锁,请确保您检查这两个消息,例如:
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
在(!)之前的IF语句中,COMMIT可以使用插入前收集的信息以及插入的信息来决定是否需要额外的处理.
在该处理步骤中,请确保将这些消息标记为已处理或将其删除仍在同一事务中.这将确保您不会两次处理这些消息.
SERIALIZABLE是允许锁定尚不存在的行的唯一事务隔离级别,所以第一个执行还在运行时,带有“WITH(UPDLOCK)”的select语句可以有效地防止其他行被插入.
最后,这些都是需要注意的事情可能会出错.你可能想看看服务代理.你可以使用三个队列.一个用于M1型,一个用于M2型.每次消息到达这些队列内时,都可以自动调用一个过程,将一个令牌插入到第三个队列中.然后,第三个队列可以激活一个进程来检查两个消息是否存在并且可以正常工作.这将使整个过程是异步的,但是由于容易限制队列3响应,因此始终只能一次执行一次检查.