插入带有序列号的表

时间:2012-07-15 08:14:33

标签: sql sql-server

如果我有以下内容:

Begin transaction
 numberOfRecords = select count from table where foreignKey = "some value" 

 Insert into table (set SequenceNumber = numberOfRecords + 1)
End Transaction

并且多个用户正在执行上述代码,每个插入都会有一个唯一的增加数字吗?

换句话说,begin事务是否排队其他事务甚至读取,以便每个插入都具有正确的序列号?或者我是否需要Insert into..Select语句来实现我想要的目标?

感谢。

5 个答案:

答案 0 :(得分:2)

不,具有默认SQL Server隔离级别(READ COMMITTED)的事务是不够的。将它放入一个INSERT...SELECT语句也不会解决它。你基本上有两种方法可以解决这个问题:

选项1 :将隔离级别设置为SERIALIZABLE:SET TRANSACTION ISOLATION LEVEL SERIALIZABLE。这将确保来自两个不同用户的事务发生,就像它们按顺序发生一样。但是,如果许多此类事务并行发生,则可能会造成死锁。

选项2 :在事务开始时(SELECT * FROM table WITH (TABLOCKX, HOLDLOCK) WHERE 1=0)独占锁定表。请注意,如果经常使用table,这可能会影响性能。

我对以下SO问题的回答详细分析了这两种方法:

答案 1 :(得分:1)

不,事务不排队命令,它不像锁。

通常你想使用一个标识列,但在某些情况下,如果你想生成没有间隙的SequenceNumber,你需要在SequenceNumber列上使用上面的代码和唯一约束,并准备在提交事务抛出一个时重试异常。

答案 2 :(得分:1)

我曾经使用SQL DB作为大规模数据导出的记录器,为了获得顺序“身份”,我创建了一个“on insert”触发器,用于发出下一个数字。 对我来说工作得很好,但它只是一个用户数据库,因此不确定是否存在多个用户和我所做的问题。

现在我已经重新阅读了这个问题,这可能不是你想要的,但我认为你也可以为选择做一个触发器?

USE [ExportLog]
GO

/****** Object:  Trigger [dbo].[Migration_Update_Event_Date]    Script Date: 02/10/2011                17:06:11 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TRIGGER [dbo].[Migration_Update_LogState]
ON [dbo].[MigrationLog] FOR INSERT NOT FOR REPLICATION
AS
UPDATE [MIGRATION-DATA].dbo.MIGRATIONSTATE
SET LASTPROCESSID = ID
WHERE MACHINENAME IN (SELECT MACHINENAME FROM INSERTED)

GO

答案 3 :(得分:1)

如果你想以唯一的方式插入记录,那么首先你要按顺序创建记录,然后记录应插入序列。似乎

create sequnce seq_num ;

现在使用seq_num插入rcords。

insert into <table name>(col1) values(seq_num.nextval);

答案 4 :(得分:1)

您需要将事务隔离级别设置为提供正确隔离级别的级别。在您的代码中,两个进程可以执行第一行,然后执行第二行。两者都会插入相同的值。

将隔离级别设置为可序列化并执行select语句WITH (UPDLOCK)。这将减少系统中的并发性,但它将是安全的。

其他策略是可行的,但实施(并测试!)会更耗时。