使用存储过程创建订单号在事务中选择和更新

时间:2016-04-07 21:38:44

标签: sql-server tsql transactions deadlock

我需要创建一种创建唯一订单号的方法。每个订单号必须始终大于最后一个,但它们不应总是连续的。该解决方案必须在Web场环境中工作。

目前有一个存储过程,负责获取新的订单号,必须对其进行播种,以使订单号不连续。应用程序现在从单个服务器转移到Web场,因此通过使用C#中的锁来控制对存储过程的访问不再可行作为控制访问的方法。我已经更新了存储过程,但是我担心在发生并发调用时我会引入blocks \ locks \ deadlocks。

表和索引结构如下

MyAppSetting Table

CREATE TABLE [dbo].[MyAppSetting](
        [SettingName] [nvarchar](255) NOT NULL,
        [SettingValue] [nvarchar](max) NOT NULL,
     CONSTRAINT [PK_MyAppSetting] PRIMARY KEY CLUSTERED 
    (
        [SettingName] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

我的订单表

    CREATE TABLE [dbo].[MyOrder](
        [id] [int] IDENTITY(1,1) NOT NULL,
        [OrderNumber] [nvarchar](50) NOT NULL CONSTRAINT [DF_MyOrder_OrderNumber]  DEFAULT (N''),
        ... rest of the table
     CONSTRAINT [PK_MyOrder] PRIMARY KEY NONCLUSTERED 
    (
        [id] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

Sql Transaction

    Set Transaction Isolation Level Serializable;

    Begin Transaction

        --Gen random number
        SELECT @Random = ROUND(((@HighSeed - @LowSeed -1) * RAND() + @LowSeed), 0)

        --Get Seed
        select @Seed = [SettingValue] FROM [MyAppSetting] where [SettingName] = 'OrderNumberSeed'

        --Removed concurrency and not required as order numbe should not exceed the seed number
        --select @MaxOrderNUmber = Max(OrderNumber) FROM MyOrder

        --if @MaxOrderNumber >= @Seed Begin
        --  Set @Seed = @MaxOrderNumber
        --end

        -- New Seed
        Set @OrderNumber = @Seed + @Random

        Update [MyAppSetting] Set [SettingValue] = @OrderNumber where [SettingName] = 'OrderNumberSeed'

        select @OrderNumber

    Commit

1 个答案:

答案 0 :(得分:0)

使用修订后的SQL,您只需选择并更新一个表。您可以在单个查询中执行此操作,以避免死锁的风险,并避免显式事务的需要。

设定:

CREATE TABLE OrderNumber ( NextOrderNumber int)
INSERT OrderNumber(NextOrderNumber) values (123)

获取下一个订单号

DECLARE @MinIncrement int = 5
DECLARE @MaxIncrement int = 50
DECLARE @Random int = ROUND(((@MaxIncrement - @MinIncrement -1) * RAND() + @MinIncrement), 0)
DECLARE @OrderNumber int

UPDATE OrderNumber 
SET @OrderNumber=NextOrderNumber, NextOrderNumber = NextOrderNumber + @Random 

SELECT @OrderNumber

我将LowSeed和HighSeed更改为MinIncrement和MaxIncrement,因为我发现这里的Seed一词令人困惑。我会使用专用于跟踪订单号的表来避免锁定MyAppSetting表上的任何其他内容。

我还要挑战订单总是增加但不是顺序的要求 - 如果没有这个GUID会更容易。 要考虑的替代方案是从某个时候获得从时间得到的订单号 - 用最后一个数字来识别不同的服务器。