【问题标题】:Serializable transaction appropriate for this scenario?适合这种情况的可序列化事务?
【发布时间】:2011-03-25 00:26:17
【问题描述】:

编辑:SQL Server 2005

我有一个客户应用程序在 5 个独立的服务器上运行。每个应用程序都在查看一个调度表。我想确保没有机器可以像任何其他机器一样同时访问相同的记录。每个服务器一次只能处理 1 行。基本上,应用程序只是选择可以运行的下一条可用记录。如果没有选择任何内容,它就什么也不做,然后再等一分钟再试一次。

[编辑:更具体地说,没有从 dbo.the_table 中删除任何行。它只是将 IsProcessing=1 标记为其他机器不会拾取它]

我的存储过程(SQL Server)如下:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRAN

SET @ScheduleId = SELECT TOP 1 ScheduleId FROM dbo.the_table WHERE NextRun <= GETDATE() AND IsEnabled = 1

UPDATE dbo.the_table SET IsProcessing=1 WHERE ScheduleId = @ScheduleId

--Edit: Return this to the program so we can do stuff with the data
SELECT * FROM dbo.the_table WHERE ScheduleId = @ScheduleId

IF @@ERROR = 0
COMMIT TRAN
ELSE
ROLLBACK TRAN

我想确定当事务正在进行时,其他机器的任何 SELECT 语句都将被阻塞,直到事务被阻塞事务提交。 (例如,机器 A 开始一个事务——如果 B、C、D 或 E 尝试并选择,它们将等到事务提交)。

【问题讨论】:

    标签: sql-server transactions serializable


    【解决方案1】:

    您使用的是哪个版本的 SQL Server?如果 SQL2005+ 你可以在一个语句中完成所有这些

    ;WITH s AS
    (
    SELECT TOP 1 * 
    FROM dbo.the_table WHERE NextRun <= GETDATE() AND IsEnabled = 1
    AND IsProcessing = 0 /*?*/
    --ORDER BY ScheduleId  ?
    )
    UPDATE    s  WITH (ROWLOCK, READPAST)
    SET     IsProcessing=1 
    OUTPUT INSERTED.*  /*Return row that was updated*/
    

    【讨论】:

    • +1 另外,我建议使用rusanu.com/2010/03/26/using-tables-as-queues,因为在这种情况下the_table 被用作队列。
    • 非常抱歉。我错过了程序的一个重要部分。我已经进行了适当的修改。
    • @Remus,感谢非常有用的链接。 @Zero - 据我所见,可以通过返回 INSERTED.* 并让程序选择行来检查 IsProcessing = 0 - 或者我错过了什么?
    • 我只是想确保通过我所做的编辑,您的解决方案仍然可行,因为我不是 SQL Server 专家。听起来您的解决方案会起作用——我还需要包含 SET TRANSACTION ISOLATION LEVEL SERIALIZABLE 并添加我的 BEGIN TRAN / COMMIT TRAN 吗?
    • @Zero - 不,你不需要这些。无论如何,它是隐式事务中的一条语句,请参阅 Remus 的链接以了解LCK_M_U 锁定以及为什么不需要更改隔离级别。
    猜你喜欢
    • 2012-01-21
    • 1970-01-01
    • 1970-01-01
    • 2016-01-06
    • 1970-01-01
    • 1970-01-01
    • 2010-11-21
    • 2023-03-10
    相关资源
    最近更新 更多