此 UPDATE 语句中是否存在可能的竞争条件?

发布于 2024-09-28 17:51:37 字数 530 浏览 6 评论 0原文

我正在编写一个同步器软件,它将获取一个数据库中的所有更改并将它们同步到另一个数据库。为此,我在表 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 的值,然后另一个用户在提交我的行之前设法在某处插入/更新了一行,该怎么办?这是有风险的代码吗?如果是的话——如何才能做得更好?

I'm writing a synchronizer software which will take all changes in one DB and synchronize them to another DB. To this end I've added in my table T two columns:

alter table T add LastUpdate rowversion, LastSync binary(8) not null default 0

Now I can easily select all rows that have changed since the last synchronization:

select * from T where LastUpdate > LastSync

However after performing the synchronization I should make the two fields equal. But updating the row also updates the timestamp, so I must do this:

update T set LastSync=@@DBTS+1 where ID=@syncedId

But I'm wondering - will this always work? What if I read the value of @@DBTS and then another user manages to insert/update a row somewhere before my row is committed? Is this risky code? And if yes - how could it be made better?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

看透却不说透 2024-10-05 17:51:37

将“LastSync”与真实数据存储在同一个表中可能根本不是一个好主意。
尝试将其存储在另一个没有行版本的表中。这样您就可以避免“更新行也会更新时间戳”的问题。

然后,您的同步器软件可以这样工作:

  • 从附加表中获取 @LastSync 值
  • "Select @ThisSync = max(LastUpdate) from T where LastUpdate > @LastSync"
  • "Select * from T where LastUpdate > @LastSync and LastUpdate < ;= @ThisSync" 是要同步的行 将
  • @ThisSync 存储为附加表中的新“LastSync”。

同步运行时修改的条目将具有比 max() 查询更高的 rowversion 值。它们将在下次调用同步器时同步。

Storing "LastSync" in the same table as the real data is maybe not a good idea at all.
Try storing it in another Table that doesn't have a rowversion. That way you avoid the "updating the row also updates the timestamp"-problem.

Your synchronizer software can then work this way:

  • Get the @LastSync value from the additional table
  • "Select @ThisSync = max(LastUpdate) from T where LastUpdate > @LastSync"
  • "Select * from T where LastUpdate > @LastSync and LastUpdate <= @ThisSync" are your rows for sync
  • Store @ThisSync as the new "LastSync" in the additional table.

Entries that are modified while the synchronization is running will have a higher rowversion value than the max() query. They will be synchronized the next time your synchronizer is called.

情话墙 2024-10-05 17:51:37

如果您在可序列化事务中运行此操作,则其他读/写操作将无法影响这些表。

RepeateableRead 也可以完成这项工作......

If you run this in a Serializable transaction then no other reads/writes will be able to affect these tables.

RepeateableRead may also do the job...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文