c# - 使用 Scope_Identitiy() 的并发插入

c# - concurrent inserts with Scope_Identitiy()

我们有十几个客户使用程序集以简单的 SQL 语句的形式将数据插入我的 SQL Server 2012。

有两个表(例如 [User][Location])有一个标识列和一个外键。

语句的执行始终是相同的:创建用户,将新的id保存为创建位置的外键。

在伪代码中:

//open DB Connection
Connection.Open();

//Insert user
"INSERT INTO User (Name, Birthdate) VALUES ("Smith", "1.1.1919");
 SELECT SCOPE_IDENTITY();" //save the new ID in var "newID"

//Execute Statement
ExecuteQuery();

//Insert Location
"INSERT INTO Location(Country, City, User_ID) VALUES ("Germany", "Cologne", newID)"

//Execute Statement
ExecuteQuery();

//close Connection
Connection.Close();

到目前为止还没有魔法...但是如果我 运行 同时在多个客户端或并行线程中使用此代码,是否有可能 SCOPE_IDENTITY() 检索新创建的 ID User 由另一个 client/thread?

创建

特别是在插入用户和 Scope_Identity() 之间是否有时间让另一个线程插入 Scope_Identity 读取的新用户?

也许 OUTPUT 子句可以替代?

澄清事情

A session 对应于您与数据库的当前连接(Ado.Net / EF / SSMS 等)。一个应用程序可能与一个数据库有多个会话。

A scope 是执行 SQL 命令的上下文。想象一下,您调用一些 T-SQL,它调用一个存储过程,它执行一些触发器。您的 T-SQL 将有一个作用域,然后是存储过程内代码的另一个嵌套作用域,然后是触发器内代码的另一个作用域。因此,当您使用 SCOPE_IDENTITY 时,您正在检索您所在范围内最后插入的 PK Id。

本质上,不同的会话意味着不同的范围。

相反,@@IDENTITY returns 会话中最后插入的 ID。这不是 "scope-aware"。如果您插入 table,并且触发器在幕后执行某些操作,您就有机会获得触发器插入的 ID。

请注意,如果您回滚已生成 PK Id 的事务,PK 计数器不会返回到以前的值,因为回滚,该行未提交,但会存在一个小洞table PK连续性...