小编典典

数据库中的原子比较和交换

sql

我正在研究工作排队解决方案。我想查询数据库中给定的行,其中状态列具有特定值,修改该值并返回该行,并且我想自动执行此操作,以便其他任何查询都不会看到它:

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的解决方案


阅读 140

收藏
2021-05-16

共1个答案

小编典典

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中的游标一起使用。

无论如何,您在原始帖子中的行为是不正确的。多个会话都可以选择同一行,甚至都可以更新它,从而将相同的出列项返回给多个读取器。

2021-05-16