【问题标题】:Can I Select and Update at the same time?我可以同时选择和更新吗?
【发布时间】:2016-04-24 17:14:04
【问题描述】:

这是对我的工作的过度简化的解释。
我有一个带有状态列的表。应用程序的多个实例将拉取状态为NEW 的第一行的内容,将状态更新为WORKING,然后继续处理内容。
使用两个数据库调用很容易做到这一点;首先是SELECT,然后是UPDATE。但我想在一次调用中完成所有操作,以便应用程序的另一个实例不会拉同一行。有点像SELECT_AND_UPDATE 的东西。

存储过程是最好的方法吗?

【问题讨论】:

    标签: sql-server


    【解决方案1】:

    您可以使用OUTPUT 语句。

    DECLARE @Table TABLE (ID INTEGER, Status VARCHAR(32))
    INSERT INTO @Table VALUES (1, 'New')
    INSERT INTO @Table VALUES (2, 'New')
    INSERT INTO @Table VALUES (3, 'Working')
    
    UPDATE  @Table
    SET     Status = 'Working'
    OUTPUT  Inserted.*
    FROM    @Table t1
            INNER JOIN (
              SELECT  TOP 1 ID 
              FROM    @Table
              WHERE   Status = 'New'
            ) t2 ON t2.ID = t1.ID
    

    【讨论】:

    • 请注意,这需要 SQL Server 2005 或更高版本。
    • 我相信作者想在交易中做一些额外的工作,但是问题中没有任何东西证实了这一点。所以+1。
    • 顺便说一句,你在这里不用JOINCTE 就足够了。
    • CTE 对我来说还不是第二天性。我仍然需要查找如何写一个。使用 JOIN,我不需要考虑。
    【解决方案2】:

    听起来像是一种队列处理方案,您希望一个进程只获取给定的记录。

    如果是这种情况,请查看我今天早些时候提供的答案,该答案描述了如何使用事务以及 UPDLOCK 和 READPAST 表提示来实现此逻辑: Row locks - manually using them

    最好用 sproc 包起来。

    我不确定这是您想要做的,因此我没有投票决定关闭为重复。

    【讨论】:

    • 这是我需要的。非常感谢。
    【解决方案3】:

    不完全是,但你可以SELECT ... WITH (UPDLOCK),然后是UPDATE..。这与原子操作一样好,因为它告诉数据库您将要更新您之前选择的内容,因此它可以锁定这些行,防止与其他客户端发生冲突。在 Oracle 和其他一些数据库(我认为是 MySQL)下,语法是 SELECT ... FOR UPDATE

    注意:我认为您需要确保这两个语句发生在事务中才能正常工作。

    【讨论】:

    • 不应该是...对于 Sql Server 有 UPDLOCK。另外,要小心,因为 UPDLOCK 提示意味着对您的数据持有锁,这在长时间运行的事务中可能会导致与其他事务的争用
    • @Jeff:是的,但从他的描述来看,这就是他想要的。确实,您确实需要小心长事务,但这是我所知道的获得原子“读取然后写入”类型行为的唯一方法。
    【解决方案4】:

    你应该在这里做三件事:

    1. 锁定您正在处理的行
    2. 确保只有这一行被锁定
    3. 不要等待锁定的记录:跳过下一条记录。

    为此,您只需发出以下命令:

    SELECT  TOP 1 *
    FROM    mytable (ROWLOCK, UPDLOCK, READPAST)
    WHERE   status = 'NEW'
    ORDER BY
            date
    
    UPDATE  …
    

    在交易中。

    【讨论】:

      【解决方案5】:

      存储过程是要走的路。您需要查看交易。 Sql server就是为这种东西而生的。

      【讨论】:

        【解决方案6】:

        是的,也许可以使用行锁提示使其与其他线程隔离,例如。

        UPDATE
        Jobs WITH (ROWLOCK, UPDLOCK, READPAST)
        SET Status = 'WORKING'
        WHERE JobID =
        (SELECT Top 1 JobId FROM Jobs WHERE Status = 'NEW')
        

        编辑:按照 Quassnoi 的建议,Rowlock 会更好,但同样的想法也适用于在一个查询中进行更新。

        【讨论】:

        • 提示不会出现在 SELECT 中吗?
        • 我不认为这有什么不同,因为这里只有一行在起作用,而且它在一个语句中。
        猜你喜欢
        • 2013-10-31
        • 2020-03-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多