2011-05-31 124 views
1

起初看起來很簡單,但我所知道的一切似乎都是錯誤的。EXEC聲明和交易範圍

望着PAQ的共識似乎是EXEC不啓動一個隱式事務,您可以測試該做的:

create procedure usp_foo 
as 
begin 
    select @@trancount; 
end 
go 

exec usp_foo; 

返回0。

如果通過這個與然而步驟T-SQL調試器@@ Transaction實際上是根據手錶內部的1個程序,雖然它確實返回0 ...

所以我認爲這是調試器的一個副作用,但後來我寫了一些代碼測試它,在表格中進行更新,然後進行更新選最大(ID)出來的,經典的:

create table nextid 
(
    id int 
) 

insert into nextid values (0) 

create procedure nextid 
as 
BEGIN 
    UPDATE nextid set id = id + 1 
    select max(id) from nextid 
END 

所以我期待在並行2個​​更新執行2個選擇提取的最後一個ID,並返回相同的值之前可以完成這個給掉重複的ID,但嘗試,因爲我可能從多臺機器打它,我不能讓它休息。當監視機器上的鎖和事務時,它會報告exec在事務中發生,重要的是,exec中的所有語句都被視爲一個工作單元/一個事務。

我會理解,如果更新是在一個事務中,這是鎖的原因,但鎖似乎一直保持,直到選擇後。

如果我用探查器跟蹤,我可以看到一個事務ID提供給EXEC語句的整個執行,和事務ID不爲0的,而執行我所期望的......

能有人請解釋對我來說,我錯過了情節,或者我錯了,事實上這是生成身份證的安全嗎?

回答

1

您的測試必須給您正確的結果,因爲您不夠快,無法調用這兩個語句之間的第二個調用。嘗試添加一個延遲,你可以看到測試將開始失敗。

CREATE TABLE NextID 
(
    ID int 
) 
GO 

INSERT INTO NextID VALUES (0) 
GO 

CREATE PROC GetNextID 
AS 
BEGIN 
    UPDATE NextID SET ID = ID + 1 
    WAITFOR DELAY '00:00:05' 
    SELECT Max(ID) FROM NextID 
END 

問題的EXEC GetNextID,一旦你從另一個會話可以發出另一個EXEC GetNextID。大約5秒鐘後,兩個EXEC都會返回相同的結果,即不正確的值。現在將SP更改爲

CREATE PROC GetNextID 
AS 
BEGIN 
    BEGIN TRAN 

    UPDATE NextID SET ID = ID + 1 
    WAITFOR DELAY '00:00:05' 
    SELECT Max(ID) FROM NextID 

    COMMIT TRAN 
END 

並重覆上述測試。你會看到這兩個調用會返回正確的值。此外,第二次調用(如果儘快發佈)會在10秒內返回結果,因爲UPDATE被阻止,必須等待5秒(對於第一次調用COMMIT),然後等待5秒鐘。

+0

啊,我已經在這個幫助下計算出來了。我正在調用輸出並將其插入散列表中。由於整個語句(包括exec)構成插入的一個隱式事務的一部分,因此它使用環境事務適當地保護了該呼叫。 很明顯,在沒有嵌入插入的情況下調用它會產生重複項。謝謝! – Cobusve 2011-06-09 13:38:26