我想实现如下的原子事务:
BEGIN TRAN A
SELECT id
FROM Inventory
WITH (???)
WHERE material_id = 25 AND quantity > 10
/*
Process some things using the inventory record and
eventually write some updates that are dependent on the fact that
that specific inventory record had sufficient quantity (greater than 10).
*/
COMMIT TRAN A
问题是还有其他交易正在消耗我们库存中的数量,因此在选择记录和更新写入事务A之间,该记录可能会成为无效选择,因为它的数量可能已降低低于WHERE子句中的阈值。
所以问题是我应该在WITH子句中使用什么锁定提示来防止在我完成更新并提交事务之前更改选定的库存记录?
编辑: 所以感谢John,一个好的解决方案似乎是将事务隔离级别设置为REPEATABLE READ。这将确保“在当前事务完成之前,没有其他事务可以修改当前事务已读取的数据。”
答案 0 :(得分:12)
实际上,您可能最好设置事务隔离级别,而不是使用查询提示。
以下联机丛书中的参考资料提供了每种不同隔离级别的详细信息。
http://msdn.microsoft.com/en-us/library/ms173763.aspx
这篇文章解释了SQL Server中各种类型的锁定行为,并提供了示例。
http://www.sqlteam.com/article/introduction-to-locking-in-sql-server
答案 1 :(得分:2)
WITH (HOLDLOCK)
允许其他读者。
其他地方建议的UPDLOCK是独家的。
HOLDLOCK将阻止其他更新,但它们可能会使用稍后更新的数据。
UPDLOCK会阻止任何人在您提交或回滚之前读取数据。
你看过sp_getapplock了吗? 这将允许您序列化此代码(如果它是唯一的更新位)而没有UPDLOCK阻止
编辑:问题主要在于此代码在2个不同的会话中运行。 使用HOLDLOCk或REPEATABLE_READ,将在第一次会话更新之前在第二个会话中读取数据。使用UPDLOCK,没有人可以在任何会话中读取数据。
答案 2 :(得分:2)
MSSQL:
SELECT id
FROM Inventory (UPDLOCK)
WHERE material_id = 25 AND quantity > 10;
http://www.devx.com/tips/Tip/13134
SELECT id
FROM Inventory
WHERE material_id = 25 AND quantity > 10
FOR UPDATE;
答案 3 :(得分:0)
我相信这将是UPDLOCK。
答案 4 :(得分:0)
锁定提示:
WITH (UPDLOCK, HOLDLOCK)