我有一个从多个线程调用的进程,它执行以下操作:
- 开始交易
IsProcessed=0
通过查找带有提示的下一行从工作表中选择工作单元(UPDLOCK, HOLDLOCK, READPAST)
- 处理工作单元(C# 和 SQL 存储过程)
- 提交交易
这样做的想法是一个线程浸入池中以获取“下一个”工作,并对其进行处理,并且锁在那里确保单个工作不会被处理两次。(顺序无关紧要)。
几个月来,所有这些都运行良好。直到今天,当我碰巧意识到尽管启用了快照隔离并将其设置为数据库级别的默认值时,实际的事务创建代码是手动设置隔离级别“ReadCommitted”。
我适时将其更改为“快照”,当然立即收到以下消息:
您只能在 READ COMMITTED 或 REPEATABLE READ 中指定 READPAST 锁
锁定行的主要原因是“标记行”,以便在提交应用标记的事务时删除“标记”,并且锁定似乎是执行此操作的最佳方式,因为这除了这些线程之外,不会以其他方式读取 table。如果我要使用 IsProcessed 标志作为锁,那么大概我需要先进行更新,然后选择我刚刚更新的行,但我需要使用 NOLOCK 标志来知道是否有任何其他线程设置了标志在一行。
一切听起来有点乱。最简单的选择是完全放弃快照隔离模式,但第 3 步的设计需要它。
关于解决这个问题的最佳方法有什么好主意吗?