代码之家  ›  专栏  ›  技术社区  ›  Ben M

使用SQL Server作为资源锁定机制

  •  1
  • Ben M  · 技术社区  · 15 年前

    给定一个逻辑资源标识符表(每行一个),对于任意数量的数据库客户端执行以下操作的最佳方法是什么:

    • 声明对特定资源的访问权限(如果尚未声明)
    • 选择下一个可用资源并声明它(与上面类似)
    • 释放以前声明的资源

    (该表将有一个“索赔人”列,在无人认领的行中为空。)

    我一直在关注这些操作的原子性:在我为请求的/下一个可用资源选择之前(然后更新,假设声明成功),我需要一个完整的表锁吗?还是有更具体的方法来做到这一点?我现在没有大量的数据,但是我希望尽可能地保持表的可访问性。

    2 回复  |  直到 14 年前
        1
  •  3
  •   Mitch Wheat    14 年前

    您基本上是在描述基于队列的经典工作流,并且应该考虑使用 queue .

    为了便于讨论,以下是您如何实现自己的愿望:

    • 声明特定资源: SELECT ... FROM resources WITH (UPDLOCK, ROWLOCK) WHERE key = @key . 如果资源已被占用,将阻止。如果资源已声明,请使用锁定超时返回异常。 key 必须 索引和唯一性。
    • 下一个可用资源: SELECT ... FROM resources WITH (UPDLOCK, ROWLOCK, READPAST) ORDER BY <accessorder> . 您必须定义order by来表示资源的首选项(最早、最高优先级等)
    • 释放声称的资源: COMMIT 您的交易。

    问题的关键是使用正确的锁提示,这种问题确实需要显式的锁提示来解决。updlock将充当“claim”锁。rowlock创建正确的粒度,防止服务器“优化”页面锁。readpass允许您跳过声明的资源。在行上放置updlock将锁定该行,并允许您稍后更新它,但会阻止其他操作,如将在锁定行上阻塞的普通读提交选择。不过,您的想法是无论如何都要更新行,这将放置一个不可避免的X锁。如果您想保持桌子的可用性,可以使用 app locks 相反,但是很难正确完成。您需要在资源的字符串描述符上请求一个应用程序锁,比如键值,或者 CHECKSUM 或者是钥匙的 %%LOCKRES%% 价值。app locks允许您通过在“session”范围请求app lock来将“claim”的范围从事务中分离出来,但是您必须手动释放claim(“transaction”范围的app locks在提交时被释放)。不过,抬头看看,有上千种方法可以用应用程序锁把自己的脚射死。

        2
  •  3
  •   Robert Christie    15 年前

    SQL Server有一个名为 sp_getapplock . 文档将其描述为

    锁定应用程序资源。

    客户机可以竞争已命名的锁(您给它指定您想要的名称),一旦锁定,就执行所需的操作。如果客户端崩溃,锁将自动释放。要以编程方式释放锁,可以调用 sp_releaseapplock

    使用AppLocks的可定位解决方案

    • 如果索赔人为空,请尝试使用相同的名称获取applock。
    • 如果获得了applock,请使用您的clasent id更新该行。
    • 一旦该行被声明,释放applock,因为没有其他客户端会尝试声明它,现在它已经被声明了。
    • 完成后,将clasent更新为空