带有nolocks的SQL事务和TRANSACTION ISOLATION LEVEL READ COMMITTED

时间:2014-06-17 20:19:36

标签: sql stored-procedures concurrency sql-server-2012

我有这样的存储过程。

CREATE PROCEDURE [dbo].[mysp] 
AS
SET NOCOUNT    ON
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
BEGIN
BEGIN TRAN

DECLARE @TrackingCode INT   

SELECT @TrackingCode = DefaultsData 
FROM dbo.Defaults  
WHERE DefaultsID=77

UPDATE dbo.Defaults
SET DefaultsData = @PassedTrackingCode+1
WHERE DefaultsID=77

SELECT @TrackingCode

COMMIT TRAN
END

假设我们同时(并发)两次执行此存储过程,那么同时返回的@TrackingCode值将是什么。如果我在存储过程中的NOLOCK语句中使用SELECT该怎么办?

1 个答案:

答案 0 :(得分:0)

1)如果您打算生成唯一的跟踪代码,那么这不是一个好主意。你可以做这个简单的测试:

CREATE TABLE dbo.Defaults (
    DefaultsData INT,
    DefaultsID INT PRIMARY KEY
);
GO
INSERT INTO dbo.Defaults VALUES (21, 77);
GO

CREATE PROCEDURE [dbo].[mysp] 
AS
SET NOCOUNT    ON
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
BEGIN
BEGIN TRAN

DECLARE @TrackingCode INT   

SELECT @TrackingCode = DefaultsData 
FROM dbo.Defaults  
WHERE DefaultsID=77

WAITFOR  DELAY '00:00:05' -- 5 seconds delay
UPDATE dbo.Defaults
SET DefaultsData = @TrackingCode+1 
WHERE DefaultsID=77

SELECT @TrackingCode -- Maybe it should return the new code

COMMIT TRAN
END;
GO

然后在SQL Server Management Studio中打开一个新窗口(Ctrl + N)并执行(F5)

EXEC [dbo].[mysp] 

并打开第二个新窗口并执行(不到5秒钟)

EXEC [dbo].[mysp] 

在这种情况下,您将获得相同的值NOLOCK是一个坏主意(一般来说),在这种情况下并不能帮到你。

2)如果(我重复自己 - 抱歉)你的意图是生成唯一的跟踪代码然后你可以使用

ALTER PROCEDURE [dbo].[mysp] 
    @TrackingCode INT OUTPUT 
AS
BEGIN
    SET NOCOUNT ON;

    UPDATE  dbo.Defaults
    SET @TrackingCode = DefaultsData = DefaultsData + 1 -- It generate the new code
    WHERE   DefaultsID=77;
END;
GO

或者您可以使用sequences(SQL Server 2012 +)。