2010-03-24 104 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所说)列。这将从任何你想要的开始并向前或向后递增。如果你需要你的订单,以一个给定的数字开始然后转发它。但是如果你需要一个唯一的标识符,并且恰好是一个整数值,那么就使用标识符。