我有一个使用事件数(除其他类型的数字)的应用程序。这些数字都存储在一个名为“Number_Setup”表,其中包含计数器的当前值。

当该应用程序产生一个新的事件,它number_setup表并获取所需数量的计数器行(计数器可以每日复位,每周等,并存储为INT的)。然后,它incremenets计数器并用新的值来更新行。

中的应用是多用户(大约100个用户在任何一个时间,以及SQL作业运行和抓住的事件记录和请求事件号100的每个)。这一事件表中有一些重复的事件数,他们不应该重复。

一个存储过程被用来检索下一个计数器。

SELECT @Counter = counter, @ShareId=share_id, @Id=id
FROM Number_Setup
WHERE LinkTo_ID=@LinkToId
AND Counter_Type='I'

IF isnull(@ShareId,0) > 0
BEGIN 
    -- use parent counter
    SELECT @Counter = counter, @ID=id
    FROM Number_Setup
    WHERE Id=@ShareID
END

SELECT @NewCounter = @Counter + 1

UPDATE Number_Setup SET Counter = @NewCounter
WHERE id=@Id

我现在已经包围该块与交易,但我不能完全肯定这将100%解决这个问题,我觉得还是有共享锁,因此计数器反正可以被读取。

也许我可以检查计数器尚未更新,在更新语句

UPDATE Number_Setup SET Counter = @NewCounter
WHERE Counter = @Counter
IF @@ERROR = 0 AND @@ROWCOUNT > 0 
    COMMIT TRANSACTION
ELSE
    ROLLBACK TRANSACTION

我敢肯定,这是在金融应用等点击发票号的一个常见问题 我不能把逻辑代码,通过并使用在该水平锁定。 我也锁定在HOLDLOCK,但我不知道它的应用。是否应该在两个SELECT语句把?

我怎样才能保证不产生重复?

有帮助吗?

解决方案

诀窍是做计数器更新,并在单个原子操作读:

UPDATE Number_Setup SET Counter = Counter+1
OUTPUT INSERTED.Counter 
WHERE id=@Id;

此虽然不分配新的计数器来@NewCounter,而是返回其作为设置成客户端的结果。如果必须分配它,使用中间表变量来输出新的计数器INTO:

declare @NewCounter int;
declare @tabCounter table (NewCounter int);
UPDATE Number_Setup SET Counter = Counter+1
OUTPUT INSERTED.Counter INTO @tabCounter (NewCounter)
WHERE id=@Id
SELECT @NewCounter = NewCounter FROM @tabCounter;

这解决了使计数器增量原子的问题。你仍然需要在你的程序中的其他竞争条件,因为LinkTo_Id和share_id仍可后的第一个更新选择这样你就可以增加了错误的链接到项目的柜台,但不能仅仅从这个代码示例,因为它依赖也解决了上actualy更新shared_id的代码和/或LinkTo_Id。

BTW你应该进入名称一致的情况下你的字段的习惯中。如果他们的的命名一致,那么你的必须的使用T-SQL代码的精确匹配情况。你的脚本现在运行良好,只是因为你有一个不区分大小写的排序规则服务器,如果部署一个区分大小写的排序规则的服务器上,你的脚本不字段/表名称错误的确切情况下,将遵循嘉豪匹配。

其他提示

你尝试使用的GUID,而不是自动递增作为唯一标识符?

如果您有ablity修改作业变得多发的记录,我将让你的计数器是标识列转变思维。然后当你的下一个记录,你可以做一个插入,并得到该表的@@身份。这将确保您获得最大数量。你也必须做一个dbccReseed,而不是重置的只是更新表计数器,当你想重置身份。唯一的问题是,你必须做100个左右的刀片,你的SQL作业的一部分,得到一组身份。这可能是太多的开销,但使用的标识列是一个保证的广告方式来获得的唯一编号。

我可能失去了一些东西,但好像你正在试图重塑已经被解决了大多数数据库技术。

而不是从Number_Setup表中的“计数器”列读取和更新,你为什么不只是使用你的计数器自动增量的主键?你永远不会有一个主键的重复值。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top