我正在研究工作排队解决方案。我想查询数据库中给定的行,其中状态列具有特定值,修改该值并返回该行,并且我想自动执行此操作,以便其他任何查询都不会看到它:
begin transaction select * from table where pk = x and status = y update table set status = z where pk = x commit transaction --(the row would be returned)
两个或多个并发查询必须不可能返回该行(一个查询执行将在状态为y的情况下看到该行)–类似于互锁的CompareAndExchange操作。
我知道上面的代码可以运行(对于SQL Server),但是交换将始终是原子的吗?
我需要一个适用于SQL Server和Oracle的解决方案
PK是主键吗?如果您已经知道主键没有运动,那么这不是问题。如果pk 是 主键,那么这就引出了一个显而易见的问题, 即 您 如何 知道要出队的商品的pk …
问题是,如果您 不 知道主键并想出队下一个“可用”(即status = y)并将其标记为出队(删除它或将status设置为z)。
正确的方法是使用单个语句。不幸的是,Oracle和SQL Server的语法不同。SQL Server语法为:
update top (1) [<table>] set status = z output DELETED.* where status = y;
我对Oracle的RETURNING子句还不太熟悉,无法给出类似于SQL的OUTPUT的示例。
其他SQL Server解决方案要求SELECT(带有UPDLOCK)上的锁提示是正确的。在Oracle中,首选途径是使用FOR UPDATE,但在SQL Server中不起作用,因为FOR UPDATE将与SQL中的游标一起使用。
无论如何,您在原始帖子中的行为是不正确的。多个会话都可以选择同一行,甚至都可以更新它,从而将相同的出列项返回给多个读取器。