我们有一个基于ASP.NET / MSSQL的Web应用程序,可生成包含连续订单号的订单。
当用户保存表单时,将按如下方式创建新订单:
如果我在单笔交易中附上上述3个步骤,如果两个客户同时保存新订单,是否会避免创建重复的订单号? (并且假设系统最终位于具有多个IIS服务器和一个MSSQL服务器的Web场中。)
由于系统中某处的并发性,我想避免两个客户选择相同的MAX(order_number)。
应该使用什么隔离级别?谢谢。
答案 0 :(得分:5)
为什么不使用Identity作为订单号?
修改强>
据我所知,您可以将当前的order_number列设为Identity(您可能需要重置种子,因为我已经这样做了一段时间)。你可能想做一些测试
Here's很好地了解了在SSMS中将列更改为Identity时实际发生的情况。作者提到如果表已有数百万行,这可能需要一段时间。
答案 1 :(得分:1)
风险是在其中一个插入新订单之前选择MAX(order_number)的两个过程。更安全的方法是一步到位:
INSERT INTO order_table
(order_number, /* other fields */)
VALUES
( (SELECT MAX(order_number)+1 FROM order_table ) order_number,
/* other values */
)
答案 2 :(得分:1)
我同意G_M;使用标识字段。添加记录时,只需
INSERT INTO order_table (/* other fields */)
VALUES (/* other fields */) ; SELECT SCOPE_IDENTITY()
Scope Identity的返回值将是您的订单号。
答案 3 :(得分:1)
使用身份是目前最好的主意。我像这样创建我的所有表:
CREATE TABLE mytable (
mytable_id int identity(1, 1) not null primary key,
name varchar(50)
)
"身份" flag表示,"让SQL Server为我分配这个号码"。 (1,1)表示身份号码应从1开始,每当有人将记录插入表格时,它将增加1。 Not Null意味着不允许任何人在此列中插入null,并且"主键"意味着我们应该在此列上创建clustered index。使用这种表格,您可以插入如下记录:
-- We don't need to insert into mytable_id column; SQL Server does it for us!
INSERT INTO mytable (name) VALUES ('Bob Roberts')
但是要回答你的字面问题,我可以就交易的运作方式提供一些教训。这样做肯定是可能的,尽管不是最佳的:
-- Begin a transaction - this means everything within this region will be
-- executed atomically, meaning that nothing else can interfere.
BEGIN TRANSACTION
DECLARE @id bigint
-- Retrieves the maximum order number from the table
SELECT @id = MAX(order_number) FROM order_table
-- While you are in this transaction, no other queries can change the order table,
-- so this insert statement is guaranteed to succeed
INSERT INTO order_table (order_number) VALUES (@id + 1)
-- Committing the transaction releases your lock and allows other programs
-- to work on the order table
COMMIT TRANSACTION
请记住,使用标识主键列声明您的表会自动为您完成此操作。