[英]Inserting into a table with sequence number
如果我有以下内容:
Begin transaction
numberOfRecords = select count from table where foreignKey = "some value"
Insert into table (set SequenceNumber = numberOfRecords + 1)
End Transaction
并且有多个用户正在执行上述代码,那么每个插入内容的编号都会增加吗?
换句话说,开始事务是否使其他事务排入队列甚至读取,以便每个插入都具有正确的序列号? 还是我需要Insert into..Select语句来实现我想要的?
谢谢。
否,具有默认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问题的回答中已详细分析了这两种方法:
不,事务不使命令排队,它不像锁。
通常,您想使用一个身份列,但是在某些情况下,当您想要无间隙地生成SequenceNumber时,您需要使用上面的代码对SequenceNumber列具有唯一约束,并准备在提交事务引发异常时重试。
我曾经使用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)
走
如果要以唯一的方式插入记录,则首先要在序列上创建,然后记录应插入thorugh序列。
create sequnce seq_num ;
现在使用seq_num
插入rcords。
insert into <table name>(col1) values(seq_num.nextval);
您需要将事务隔离级别设置为提供正确隔离级别的级别。 在您的代码中,两个进程可以执行第一行,然后执行第二行。 两者将插入相同的值。
将隔离级别设置为可序列化,然后执行select语句WITH (UPDLOCK)
。 这样可以减少系统中的并发性,但是很安全。
其他策略也是可能的,但是它们实施(和测试!)的时间更长。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.