在多线程环境中的 SQL Server 中插入后获取 ID?

Posted

技术标签:

【中文标题】在多线程环境中的 SQL Server 中插入后获取 ID?【英文标题】:Get Id after an INSERT in SQL Server in a multithread enviromment? 【发布时间】:2010-10-12 07:05:01 【问题描述】:

如何在 SQL Server 中插入后获取 id?

对于我的插入,我使用context.ExecuteStoreCommand()

警告:我有一个多线程应用程序,它“同时”在同一个表中插入一些数据。

【问题讨论】:

【参考方案1】:
SELECT SCOPE_IDENTITY()

在您的插入语句之后使用它,它将返回您在您的范围内插入的标识。您可以将其分配给变量或在输出参数中返回。

【讨论】:

是的。查看msdn.microsoft.com/en-us/library/ms190315.aspx 了解SCOPE_IDENTITY 的详细文档 SCOPE_IDENTITY() 与@@identity 有何不同,SCOPE_IDENTITY() 本身返回@@identity... 在我的回答中,我在插入后返回了@@identity...跨度> SELECT SCOPE_IDENTITY() 在我的 INSERT 之后返回 null ?! context.ExecuteStoreQuery("SELECT SCOPE_IDENTITY()") 您应该在相同的上下文中调用您的插入语句和执行查询,例如: context.ExecuteStoreQuery("insert into table values(...); SELECT SCOPE_IDENTITY()")【参考方案2】:

对于这种情况,您应该使用Scope_Identity()。这将返回当前范围的标识。 @@Identity 返回最后插入的标识。

看看Scope Identity on MSDN - 与使用Scope_Identity相比,@@Identity 将返回错误值的示例

【讨论】:

【参考方案3】:

试试这个

@@identity

下面的示例代码

strSQL = "INSERT INTO tablename (name) VALUES (@name);SELECT @@Identity"
SQLCommand.CommandText = strSQL
Id = SQLCommand.ExecuteScalar()

【讨论】:

@Numenor - 你在说什么?这是完全线程安全的,因为两个命令都在一个查询中执行。 @Patrice Pezillier,你怎么说这不是线程安全的......你检查过插入语句吗?? @Ramesh - 在 MS SQL Server 中检索身份值时,您应该始终使用 Scope_Identity() 而不是 @@Identity。 Scope_Identity 返回当前作用域的标识值,@@Identity 返回最后插入的标识。在当前范围内可能已插入也可能未插入。有关示例,请参阅msdn.microsoft.com/en-us/library/ms190315.aspx (没有投票)- SCOPE_IDENTITY 比@@IDENTITY 更受欢迎,主要是因为触发器的问题。但是那些声称它不是线程安全的也是错误的,并且可能正在考虑 IDENT_CURRENT @Barry,谢谢你的链接,我明白了。但在这种情况下,范围是单一的,所以不会造成任何问题......【参考方案4】:

另一种实现方法是使用 T-SQL 语言的OUTPUT 子句。

例如:

create table #tmpTable 
(
    ID int identity(1,1) not null primary key,
    SomeValue varchar(20) not null
);

insert #tmpTable
output INSERTED.ID
values('SomeTextData')

drop table #tmpTable;

从整体解决方案设计的角度来看,我建议您将插入逻辑包装到您从应用程序源代码调用的存储过程(返回插入的记录 ID)中。

【讨论】:

【参考方案5】:

我认为您可以编写一个具有输入/输出参数的存储过程,然后从参数中获取值。

【讨论】:

【参考方案6】:

如果您需要标识值,我很确定您会想要使用ObjectContext.ExecuteStoreQuery 方法,而不是ObjectContext.ExecuteStoreCommand。

您需要使用SCOPE_IDENTITY(),而不是@@IDENTITY,因为SCOPE_IDENTITY() 返回当前执行范围的标识值,而@@IDENTITY“是一个系统函数,它返回最后一个-插入的标识值。”

这样的事情应该可以解决问题:

using(var context = GetAContextThatsReadyToUse())

    var valueForColumn1 = 5;
    var result = ExecuteStoreQuery<int>("INSERT INTO table1 (Column1) VALUES (0);SELECT SCOPE_IDENTITY()", valueForColumn1);

    foreach(var item in result)
    
        // Should only return one result, which is the identity value inserted by ExecuteStoreQuery
        Console.WriteLine(item);
    

【讨论】:

【参考方案7】:

我遇到过很多情况,比如 100 个进程一次在一张表上写入。我没有使用SCOPE_IDENTITY(),而是将整个插入/ID 提取包装到一个事务中,这种方法没有任何问题。

【讨论】:

【参考方案8】:

参考SQL Server - Return value after INSERT

INSERT INTO table (name)
OUTPUT Inserted.ID
VALUES('bob');

【讨论】:

以上是关于在多线程环境中的 SQL Server 中插入后获取 ID?的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 在多个线程中插入死锁

scanf(), std::cin 在多线程环境中的行为如何?

iPhone:在多线程环境中发布 UIViewController 时出现问题

如何在多线程环境下实现FIFO队列?

如何保证单例模式在多线程中的线程安全性

在多线程系统中使用静态 java.sql.Connection 实例是不是安全?