假设我有一个看起来像这样的简单存储过程(注意:这只是一个例子,不是一个实际的过程):
CREATE PROCEDURE incrementCounter AS DECLARE @current int SET @current = (select CounterColumn from MyTable) + 1 UPDATE MyTable SET CounterColumn = current GO
我们假设我有一个名为'myTable'的表,其中包含一行,'CounterColumn'包含我们当前的计数.
这个存储过程可以同时执行多次吗?
即这是可能的:
我称之为'incrementCounter'两次.调用A到达设置'当前'变量的位置(假设它是5).调用B到达设置"当前"变量(也将是5)的点.呼叫A完成执行,然后呼叫B结束.最后,该表应包含值6,但由于执行的重叠而包含5
这适用于SQL Server.
每个语句都是原子的,但是如果你希望存储过程是原子的(或者一般的任何语句序列),你需要用
BEGIN TRANSACTION
Statement ...
Statement ...
COMMIT TRANSACTION
(通常使用BEGIN TRAN和END TRAN.)
当然,根据其他正在发生的事情,有很多方法可以解决锁定问题,因此您可能需要一种策略来处理失败的事务.(完全讨论可能导致锁定的所有情况,无论你如何设计这个特定的SP,都超出了问题的范围.)但是由于原子性,它们仍然会被重新提交.根据我的经验,您可能会很好,不知道您的交易量和数据库上的其他活动.请原谅我说明显的.
与流行的误解相反,这将适用于您的默认事务级别设置.
除了放置之间的代码BEGIN TRANSACTION
和END TRANSACTION
,你需要确保你的事务隔离级别设置正确.
例如,SERIALIZABLE
隔离级别将防止代码同时运行时丢失更新,但READ COMMITTED
(SQL Server Management Studio中的默认值)不会.
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
正如其他人已经提到的那样,在确保一致性的同时,这可能导致阻塞和死锁,因此可能不是实践中的最佳解决方案.