1

我有一张桌子,有两列

key -> Primary Key, auto incremented
reqNumber -> This is a custom generated value

reqNumber 的结构为年/月/日/数字,其中数字是当天发出请求的次数。因此,例如,如果今天发出 3 个请求,昨天发出 2 个请求,则该表将

key    reqNumber
1      2013/07/16/001
2      2013/07/16/002
3      2013/07/17/001
4      2013/07/17/002
5      2013/07/17/003

我遇到的问题是有时多个用户同时保存。执行保存的 proc 首先检查今天创建了多少个,然后将其加 1,因此对于上面的内容,它会看到今天创建了 3 个,因此下一个将是 4 个。之后它会进行插入。

但是如果两个用户同时点击保存,他们都得到 4,这意味着当插入发生时,我得到 2013/07/17/004 两次。

有没有办法在 SQL 或 .Net 中避免这种情况?锁是唯一的方法吗,那些会降低性能的正确方法?

4

3 回答 3

3

如果您希望应用程序能够扩展,您将需要创建一个新表:

CREATE TABLE DayCounter (
    LastReset DateTime NOT NULL,
    NextValue INT NOT NULL
)

然后,您将需要一个FUNCTION,以便您可以随意获得下一个可用值:

CREATE FUNCTION NextCounter()
    RETURNS CHAR(3)
AS
BEGIN
    BEGIN TRANSACTION
        DECLARE @LastReset DATETIME
        DECLARE @NextValue INT

        SELECT @LastReset = LastReset FROM DayCounter
        IF (DATEPART(DAY, DATEADD(DAY, 1, @LastReset)) = DATEPART(DAY, GETDATE())
            UPDATE DayCounter SET LastReset = GETDATE(), NextValue = 1

        SELECT @NextValue = NextValue FROM DayCounter
        UPDATE DayCounter SET NextValue = NextValue + 1
    COMMIT TRANSACTION

    RETURN RIGHT('000' + CAST(@NextValue AS CHAR), 3)
END

因此,现在您可以构建一个更新语句,将您的值串在一起,但它不会发生冲突,并且每天都会管理重置。

于 2013-07-17T14:48:31.063 回答
1

如果 reqNumber 必须是唯一的,那么数据库应该UNIQUE对列有一个约束。添加它为您提供了另一种选择:不加锁尝试一次,如果插入失败,请使用锁重试。凭借高读/写比率和低冲突频率,这可以比每次事务解决方案执行得更好。

于 2013-07-17T16:11:36.933 回答
1

首先,我会围绕选择和更新进行交易。

其次,我只会使用乐观断开锁(意思是update table where key = TheKey and reqNumber = TheValueYouSelectedToCount)进行更新,并确保您更新了一行。如果您更新了 0 行,则意味着其他人已经更新了它。

这样您就不能“丢失”更新

于 2013-07-17T14:42:11.010 回答