2010-03-24 33 views
1

我有一個網站,供商店的所有分支機構使用,它所做的是將客戶購買記錄到名爲myTransactions.myTransactions表的一個名爲SerialNumber的表中。對於每筆購買,我在交易表中創建一個記錄併爲其分配一個序列。執行此操作的存儲過程在插入記錄之前調用UDF函數以獲取新的serialNumber。如下圖所示:可序列化的事務隔離級別不適用於我


Create Procedure mytransaction_Insert 
as begin 
insert into myTransactions(column1,column2,column3,...SerialNumber) 
values(Value1 ,Value2,Value3,...., getTransactionNSerialNumber()) 
end 

Create function getTransactionNSerialNumber 
as 
begin 
RETURN isnull(SELECT TOP (1) SerialNumber FROM myTransactions READUNCOMMITTED 
ORDER BY SerialNumber DESC),0) + 1 
end 

該網站在同一時間被使用在不同的店這麼多的用戶,它是創造了許多重複的serialNumbers(相同SerialNumbers)。所以我在事務中添加了一個具有ReadCommitted級別的Sql事務,並且我仍然有重複的事務編號。我將其更改爲SERIALIZABLE以鎖定資源,並且我不僅獲得了重複的事務數(!!如何!!),而且在相同的存儲過程調用之間也有零星的死鎖。這是我的嘗試:(使用try catch塊的遺漏和回滾)

Create Procedure mytransaction_Insert 
as begin 
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE 
BEGIN TRASNACTION ins 
insert into myTransactions(column1,column2,column3,...SerialNumber) 
values(Value1 ,Value2 , Value3, ...., getTransactionNSerialNumber()) 
COMMIT TRANSACTION ins 
SET TRANSACTION ISOLATION READCOMMITTED 
end 

我甚至複製的直接獲取序列號到存儲過程,而不是UDF函數調用的函數,還是把重複serialNumbers。那麼,一個存儲過程如何創建一些類似於c#lock(){}的塊。 順便說一下,我必須使用相同的模式來實現事務序列號,並且我不能將serialNumber更改爲任何其他身份字段或任何內容。出於某些原因,我需要在數據庫中生成serialNumber,將SerialNumber生成轉移到應用程序級別。


對不起,但我已經嘗試過,沒有READUNCOMMITTED函數,我仍然得到重複SerialNumbers。

至於IDENTITY專欄,我應該說這個應用程序將被其他需要不同SerialNumbers的公司使用,我們不能簡單地將其改爲身份。

回答

5

您在UDF中有READUNCOMMITTED。這將導致它忽略其他交易持有的任何排他鎖。

SET TRANSACTION ISOLATION LEVEL SERIALIZABLEapplock不一樣,它不是數據庫中的「關鍵部分」,它只是控制事務中後續語句的鎖定行爲。

取出READUNCOMMITTED,它應該開始按預期工作。

當然,這忽略了你實質上重新實施了IDENTITY列的事實。如果您的序列號確實是遞增的,那麼您應該丟棄所有這些,並用簡單的IDENTITY列替換它。你聲稱你「不能」,但沒有爲該聲明提供任何理由;它看起來像我幾乎可以肯定你可以

+0

感謝您的sp_getapplock引用。我不知道這樣的事情存在! – zvolkov 2011-02-28 15:49:01

0

您缺少的是您的交易表中唯一的約束(或主鍵)。如果您嘗試提交重複條目時會退出。

但我會清楚地說明你應該使用SQL中的「Identity」(如@Aaronaught所說)列。這將從任何你想要的開始並向前或向後遞增。如果你需要你的訂單,以一個給定的數字開始然後轉發它。但是如果你需要一個唯一的標識符,並且恰好是一個整數值,那麼就使用標識符。