【问题标题】:Something like LOCK statement in SQL Server类似于 SQL Server 中的 LOCK 语句
【发布时间】:2019-11-25 00:37:03
【问题描述】:

我需要在 C# 中生成类似于 lock 的语句,这是一个可以包含多个操作的同步范围。假设我有一个表GeneratedKeys 来跟踪数据库为其他一些表生成的所有会话密钥。它有一个主键列[Key]和一个用户自定义函数dbo.GenerateKey(),可以生成下一个随机键。我只想插入唯一的键,所以我必须验证生成的键的唯一性,因此我必须重新生成它,直到它变得唯一。这需要一个同步块,因为这里发生了几个操作。我的做法:

WHILE (1 = 1)
 BEGIN
   DECLARE @newKey CHAR(10) = dbo.GenerateKey();
   DECLARE @existingKey CHAR(10) = NULL;

   SELECT TOP 1 @existingKey = [entry].[Key]
   FROM [dbo].[GeneratedKeys] [entry] WITH (TABLOCKX, HOLDLOCK)
   WHERE [entry].[Key] = @newKey

   -- go to re-generate if matched
   IF @existingKey IS NOT NULL 
         CONTINUE;

   -- insert only a unique key 
   INSERT INTO [dbo].[GeneratedKeys]([Key], [CreatedOnUtc])
      OUTPUT [INSERTED].[Key] [Key]
   SELECT @newKey, GETUTCDATE()

   BREAK;
END

我的问题是 - 我是否选择了正确的锁定提示组合?首先,获取整个表的TABLOCKX 排他锁,并将其扩展到HOLDLOCK 剩余块的末尾。

【问题讨论】:

  • 将其包装在事务中并删除holdlock - 独占表锁会持续其所在事务的持续时间。 Example
  • 无需费心去做这一切,只需使用NEWID(),它几乎可以保证是独一无二的。
  • 你可以在键列上放一个唯一索引,让插入失败,然后重试。
  • 为什么不只使用标识列?它每次都会产生唯一的数字。
  • 我只需要字符串,不需要数字

标签: c# sql .net sql-server


【解决方案1】:

我们遵循以下方法来确保当有多个并发请求进入数据库时​​只执行一个请求。基本上就像在C#中模拟锁定场景。

CREATE PROCEDURE [dbo].[GetSequenceNumber]
AS
BEGIN
    SET NOCOUNT ON
    BEGIN TRANSACTION
    BEGIN TRY

            UPDATE [Rcon.Drawing].[dbo].[TableForLock] WITH (UPDLOCK) set LockValue = LockValue where LockName = 'Dummy'

        -- Logic to generate the next sequence number based on the existing value in the database

        COMMIT TRANSACTION
    END TRY
    BEGIN CATCH
            ROLLBACK TRANSACTION
            PRINT ERROR_NUMBER()
            PRINT ERROR_MESSAGE()
    END CATCH
END

我知道这可能不是完美的解决方案,但它适用于我的情况。请注意锁,否则会陷入死锁状态。

【讨论】:

    猜你喜欢
    • 2018-09-23
    • 2013-02-28
    • 2020-12-19
    • 1970-01-01
    • 1970-01-01
    • 2012-03-26
    • 1970-01-01
    • 1970-01-01
    • 2012-07-13
    相关资源
    最近更新 更多