1

如果我有以下情况:

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

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

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

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

谢谢。

4

5 回答 5

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 问题的回答中,对这两种方法都进行了详细分析:

于 2012-07-15T10:29:48.013 回答
1

我曾经使用 SQL DB 作为记录器来导出大量数据,为了获得顺序的“身份”,我创建了一个“插入时”触发器来处理发出下一个数字。对我来说效果很好,但是它只是一个用户数据库,所以不确定多个用户是否有任何问题以及我做了什么。

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

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)

于 2012-07-15T08:50:28.423 回答
1

如果你想以唯一的方式插入记录,那么首先你按顺序创建,然后记录应该插入到序列中。就像

create sequnce seq_num ;

现在用于seq_num插入 rcords 。

insert into <table name>(col1) values(seq_num.nextval);
于 2012-07-15T09:53:26.030 回答
1

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

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

于 2012-07-15T08:17:59.700 回答
1

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

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

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

于 2012-07-15T10:23:13.447 回答