此 UPDATE 语句中是不是存在可能的竞争条件?
Posted
技术标签:
【中文标题】此 UPDATE 语句中是不是存在可能的竞争条件?【英文标题】:Is there a possible race condition in this UPDATE statement?此 UPDATE 语句中是否存在可能的竞争条件? 【发布时间】:2011-04-29 02:39:12 【问题描述】:我正在编写一个同步器软件,它将获取一个数据库中的所有更改并将它们同步到另一个数据库。为此,我在表格T
中添加了两列:
alter table T add LastUpdate rowversion, LastSync binary(8) not null default 0
现在我可以轻松地选择自上次同步以来发生变化的所有行:
select * from T where LastUpdate > LastSync
但是在执行同步之后,我应该使两个字段相等。但是更新行也会更新时间戳,所以我必须这样做:
update T set LastSync=@@DBTS+1 where ID=@syncedId
但我想知道 - 这会一直有效吗?如果我读取了@@DBTS
的值,然后另一个用户在我的行被提交之前设法在某处插入/更新了一行怎么办?这是有风险的代码吗?如果是的话 - 怎样才能做得更好?
【问题讨论】:
顺便问一下,您使用的是哪个版本的 SQL Server? Change Data Capture 是一个选项吗? @Martin Smith - 2008 年,我想。不确定客户有什么。 @Martin Smith - 我检查了变更数据捕获,但那将是矫枉过正。一个简单的时间戳就足够了。我只需要知道哪些记录还需要同步。我不需要完整的历史记录。 【参考方案1】:将“LastSync”存储在与真实数据相同的表中可能根本不是一个好主意。 尝试将其存储在另一个没有行版本的表中。这样您就可以避免“更新行也会更新时间戳”的问题。
您的同步器软件可以这样工作:
从附加表中获取@LastSync 值 “选择@ThisSync = max(LastUpdate) from T where LastUpdate > @LastSync” "Select * from T where LastUpdate > @LastSync 和 LastUpdate 将@ThisSync 存储为附加表中的新“LastSync”。在同步运行时修改的条目将具有比 max() 查询更高的 rowversion 值。下次调用同步器时,它们将被同步。
【讨论】:
这是一个想法。我会记住的,以防没有更好的结果。【参考方案2】:如果您在 Serializable
事务中运行此操作,则其他读取/写入操作将无法影响这些表。
RepeateableRead
也可以完成这项工作...
【讨论】:
表格 - 是的。但是@@DBTS
的值呢?这不存储在任何表中!
@Vilx 如果您在同步期间使用排他表锁,那么@@DBTS
是否被另一个表中的事件递增可能并不重要。
@Martin Smith - 但@@DBTS 对于整个数据库来说是全局的。为什么没关系?如果我为 LastSync
字段获得一个(旧)值,而为 LastUpdate
字段获得一个新值,我的同步将被破坏。
@Vilx 好吧,如果您更新表并且 @@DBTS
的值为 10,那么另一个表会更新几行,使 @@DBTS
的值等于 12,您最终会存储 12在LastSync
字段中,为什么这是个问题?下次您进行同步时,您仍在寻找 LastUpdate > LastSync
所在的行。
@Martin Smith - 问题是反过来。 LastUpdate
获得 之后 LastSync
的值。否则,我首先不需要在查询中使用 +1
。以上是关于此 UPDATE 语句中是不是存在可能的竞争条件?的主要内容,如果未能解决你的问题,请参考以下文章