【发布时间】:2017-07-16 22:39:06
【问题描述】:
我有一个跟踪“签出”对象的表,但对象存在于其他各种表中。目标是允许用户签出符合他们标准的对象,这样一个给定的对象只能被签出一次(即没有两个用户应该能够签出同一个对象)。在某些情况下,一个对象可能跨越多个表,需要使用连接来检查所有用户的标准(如果有问题的话)。
这是一个非常简单的示例查询(希望您可以推断出架构):
update top (1) Tracker
set IsCheckedOut = 1
from Tracker t
join Object o on t.ObjectId = o.Id
join Property p on p.ObjectId = o.Id
where t.IsCheckedOut = 0
and o.SomePropertyColumn = 'blah'
and p.SomeOtherPropertyColumn = 42
由于from 子查询,我怀疑这个查询不是原子的,因此两个用户同时请求相同风格的对象最终可能会签出同一个对象。
这是真的吗?如果是这样,我该如何解决这个问题?
我考虑过添加一个output DELETED.* 子句并让用户在IsCheckedOut 列的返回值为1 时重试他们的查询,我认为这会起作用(如果我错了,请纠正我)...但是我想得到一些用户不必担心重试的东西。
编辑
有关详细说明,请参阅下面 SqlZim 的答案,但对于这个简单的情况,我可以直接将提示添加到上面发布的查询中:
update top (1) Tracker
set IsCheckedOut = 1
from Tracker t (updlock, rowlock, readpast)
join Object o on t.ObjectId = o.Id
join Property p on p.ObjectId = o.Id
where t.IsCheckedOut = 0
and o.SomePropertyColumn = 'blah'
and p.SomeOtherPropertyColumn = 42
【问题讨论】:
-
介意用给定的例子更具体地充实一下吗?如果结果是正确的,我会接受它作为答案。
标签: sql sql-server join atomic sql-update