我们有十几个客户端使用程序集以简单的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()
可能会检索User
的新创建的ID由另一个客户/线程创建?
特别是在插入用户和Scope_Identity()
之间有另一个线程来插入Scope_Identity
读取的新用户吗?
可能是OUTPUT
条款的另一种选择吗?
答案 0 :(得分:2)
澄清事情
session
对应于您对数据库的当前连接(Ado.Net / EF / SSMS等)。应用程序可能有多个数据库会话。
scope
是执行SQL命令的上下文。想象一下,你调用一些调用存储过程的T-SQL,它执行一些触发器。您的T-SQL将有一个范围,然后是存储过程中代码的另一个嵌套范围,然后是触发器内代码的另一个范围。因此,当您使用SCOPE_IDENTITY
时,您将在您所在的范围内检索最后插入的PK Id。
本质上,不同的会话意味着不同的范围。
相反,@@IDENTITY
返回会话中最后插入的ID。它不是"范围感知"。如果您在表格中插入,并且触发器在场景后面执行某些操作,则您有机会通过触发器插入ID。
请注意,如果您回滚已生成PK Id的事务,则PK计数器不会返回到先前的值,因为回滚而没有提交该行,但是会存在一个小漏洞表PK连续性......