使用存储过程 select 创建订单号并在事务中更新
Create Order Number using a Stored procedure select and update within a transaction
我需要创建一种创建唯一订单号的方法。每个订单号必须始终大于最后一个,但它们不应始终连续。该解决方案必须在网络场环境中运行。
目前有一个存储过程负责获取新的订单号,必须对订单号进行播种,以使订单号不连续。该应用程序现在正从单个服务器移动到网络场,因此通过使用 C# 中的锁来控制对存储过程的访问不再是一种可行的控制访问方法。我已经更新了存储过程如下但是我担心我将在并发调用发生时引入 blocks\locks\deadlocks。
table和索引结构如下
MyAppSettingTable
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]
我的订单table
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 交易
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
修改后的 SQL 您只提供了 select 并更新了一个 table。您可以在单个查询中执行此操作,这应该避免死锁的风险,并避免需要显式事务。
设置:
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 令人困惑。我会使用 table 专用于跟踪订单号,以避免在 MyAppSetting table.
上锁定任何其他内容
我还会质疑订单总是增加但不是顺序增加的要求 - 没有这个 GUID 会更容易。
要考虑的替代方案是以某种方式从时间派生的订单号 - 用最后一位数字来标识不同的服务器。
我需要创建一种创建唯一订单号的方法。每个订单号必须始终大于最后一个,但它们不应始终连续。该解决方案必须在网络场环境中运行。
目前有一个存储过程负责获取新的订单号,必须对订单号进行播种,以使订单号不连续。该应用程序现在正从单个服务器移动到网络场,因此通过使用 C# 中的锁来控制对存储过程的访问不再是一种可行的控制访问方法。我已经更新了存储过程如下但是我担心我将在并发调用发生时引入 blocks\locks\deadlocks。
table和索引结构如下
MyAppSettingTable
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]
我的订单table
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 交易
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
修改后的 SQL 您只提供了 select 并更新了一个 table。您可以在单个查询中执行此操作,这应该避免死锁的风险,并避免需要显式事务。
设置:
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 令人困惑。我会使用 table 专用于跟踪订单号,以避免在 MyAppSetting table.
上锁定任何其他内容我还会质疑订单总是增加但不是顺序增加的要求 - 没有这个 GUID 会更容易。 要考虑的替代方案是以某种方式从时间派生的订单号 - 用最后一位数字来标识不同的服务器。