奇怪的@@ IDENTITY范围行为?

时间:2012-05-17 08:27:48

标签: sql-server identity-column

这不是一个完整的瓶子,但我的印象是@@ IDENTITY给出了数据库中创建的最后一个身份的值,无论在哪里。 SCOPE_IDENTITY()给出当前语句范围内的值。

我有一个带有标识列的表。没有触发器,只有一个vanilla表和主索引。我在两个单独的浏览器标签中运行此Web应用程序代码:

Dim connDb As New SqlConnection(myconnectionstring)
Dim transDb As SqlTransaction = connDb.BeginTransaction()
Dim cmdInsert As New SqlCommand("INSERT INTO mytable (somecolumn) VALUES (somevalue)", conn, transDb)
Dim cmdGetIdentity As New SqlCommand("SELECT @@IDENTITY", connDb, transDb)
' Add the record, pause, get identity.
Dim iNewHosp As Int32 = cmdInsert.ExecuteNonQuery() ' Returns 1 correctly.
Threading.Thread.Sleep(5000) ' Give the other tab time to add a record.
Dim iNewID As Int32 = cmdGetIdentity.ExecuteScalar ' Returns the new ID.
' Commit trans, close, dispose, etc..

请注意,这一切都是在事务中完成的,不确定是否会产生影响。在这里使用SQL Server 2000(不幸的是)。在SQL2008中也尝试过,同样的事情发生了。

所以我在一个浏览器选项卡中运行该页面,然后在它休眠时,在另一个选项卡中再次运行它,这会添加另一个记录。我看到的“问题”是第一个选项卡然后返回其INSERT的正确的 ID,其他选项卡也是如此。我认为第一个选项卡将返回最新插入的ID,即。在第二个标签中完成的那个?

我最初尝试使用SCOPE_IDENTITY(),但它返回NULL,因此我尝试了@@ IDENTITY,看看发生了什么。所以我有两个问题 - 为什么SCOPE_会返回NULL,为什么@@ IDENTITY会返回特定于范围的结果?

2 个答案:

答案 0 :(得分:4)

不,@@IDENTITY仍限于在同一会话中生成的身份值。请参阅SCOPE_IDENTITY中的讨论:

  

SCOPE_IDENTITY@@IDENTITY会返回当前会话中任何表格中生成的最后一个身份值。但是,SCOPE_IDENTITY返回仅在当前范围内插入的值; @@IDENTITY不限于特定范围。

(强调补充)

范围≠会话。这里,范围指的是例如, @@IDENTITY将返回触发器中INSERT生成的标识值。正如您还应该看到的,您的最终选项是IDENT_CURRENT,它允许您查询特定表中的最新标识值,而不管会话。

答案 1 :(得分:0)

您正在进行Transacation中的记录插入,因此SCOPE_IDENTITY仅限于该交易。所以你无法看到从其他交易中插入的价值。

当为第二个标签提交事务时,您将能够看到第二个标签插入的标识。

SELECT SCOPE_IDENTITY()

它返回在连接上生成的最后一个IDENTITY值以及同一范围内的语句,而不管生成该值的表。 与@@ IDENTITY一样,SCOPE_IDENTITY()将返回在当前会话中创建的最后一个标识值,但它也会将其限制为当前范围。换句话说,它将返回您显式创建的最后一个标识值,而不是由触发器或用户定义函数创建的任何标识。

相关问题