以下是一些想法。我不认为它们中的任何一个是完美的 - 我认为你需要给自己一组用例并尝试它们。这是我在应用锁之后尝试的一些情况:
- 将WHERE过滤器作为另一组进行SELECT
- 将WHERE过滤器作为锁定组进行SELECT
- 对具有WHERE子句的表进行更新,作为另一组
- 对未锁定ID(而不是GrpID)的表进行更新
- 对已锁定行的表进行更新(例如,ID为1和2)
- 将数据插入具有该GrpId的表中
我有一种奇怪的感觉,这些都不会是100%的解决方案,但最有可能的答案是第二个(设置事务隔离级别)。它可能会锁定更多不必要的内容,但会给您所需的隔离。
还有一件事要记住:如果您锁定了许多行(例如,有数千行具有您想要的GrpId),则SQL Server可以将锁升级为全表锁定。(我相信临界点是5000个锁,但不确定)。
老派的黑客工作
在您的交易开始时,以某种方式更新所有相关行,例如:
BEGIN TRAN
UPDATE YourTable
SET GrpId = GrpId
WHERE GrpId = N'G1';
COMMIT TRAN;
没有别的东西可以使用它们,因为(太棒了!)它们是在事务内写入的。
方便-设置隔离级别
请参考https://learn.microsoft.com/en-us/sql/relational-databases/sql-server-transaction-locking-and-row-versioning-guide?view=sql-server-ver15#isolation-levels-in-the-。
在您的事务之前,将隔离级别设置高,例如SERIALIZABLE。
您可能希望在事务开始时读取所有相关行(例如SELECT Grp FROM YourTable WHERE Grp = N'Grp1'
)以防止它们被更新。
灵活,但需要大量编码。
使用
sp_getapplock和
sp_releaseapplock进行资源锁定。
这些用于锁定资源,而不是表格或行。
什么是资源?嗯,任何你想要的东西。在这种情况下,我建议使用'Grp1'、'Grp2'等。它实际上并没有锁定行。相反,你要求(通过sp_getapplock或APPLOCK_TEST)是否可以获取资源锁定。如果可以,继续。如果不行,则停止。
任何引用这些表格的代码都需要进行审查,并可能修改为询问是否允许运行。如果有什么东西不询问就直接运行,那么除了通过你明确指定的任何事务外,实际上并没有真正的锁定它。
你还需要确保错误得到适当处理(例如,仍然释放 app_lock)并且阻塞的进程会重新尝试。