并发环境下原子删除无死锁

问题描述 投票:0回答:1

我们有一项定期工作:

  • 加载要处理的实体列表,并且对于每个实体:
  • 在外部服务中调用可能耗时的操作
  • 如果该操作成功,则在处理实体时将其删除,并且不必在下一个作业迭代中进行处理。

删除实体可以通过多个 SQL 命令来实现。为了确保如果操作成功,实体会被可靠地删除,我们将每个实体的处理包装在数据库事务中:

open transaction
execute DB commands to delete the entity
execute the external operation
commit the transaction

请注意,我们在运行操作之前删除了实体。否则,如果操作成功但由于某种原因随后的数据库更新失败,我们将再次处理该实体,这是不希望的。 如果外部操作失败,则会引发异常,从而阻止事务提交(有效地回滚事务并撤消“将实体标记为已处理”)。

问题是外部操作有时会运行很长时间,而我们希望加快所有实体的处理速度。 我尝试并行处理实体,但偶然发现了一个问题: 显然,当删除一个实体时,数据库锁会被放置到整个表或大范围的行上(我还没有研究过这一点)。这会导致并行运行的数据库删除失败并超时,因为它们被阻止等待长时间运行的操作周围的事务提交。

是否可以在外部操作成功时保留实体的原子删除并加快所有实体的处理速度?

数据库是 MSSQL 服务器。

我的一个想法是更改实体标记为已处理的方式:不是删除它,而是添加指示成功处理的特定数据库记录。希望这不会放置如此宽的锁,也不会阻止其他线程添加此类记录。有没有其他/更好的方法?

sql sql-server locking
1个回答
0
投票
每当你“开始交易”时,你本质上是在要求出现死锁问题。 “开始交易”的核心目的是保留记录并拒绝其他人访问。这里的中心目的是死锁的根本原因。

但是可能还有另一种方法可以做你想做的事。考虑一下这个。

首先。使用输出子句执行删除。将删除的条目放入暂存表中。

第二。然后,执行外部操作。

第三。执行外部操作后,从暂存表中删除已删除的条目。

顺便说一句,由于您的整体逻辑没有描述“回滚”场景,除非您之前没有描述过“回滚”场景,所以“begin tran”无论如何都是新的,对您没有任何帮助。

© www.soinside.com 2019 - 2024. All rights reserved.