【问题标题】:Strange @@IDENTITY scope behaviour?奇怪的@@IDENTITY 范围行为?
【发布时间】:2012-05-17 08:27:48
【问题描述】:

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

我有一个带有标识列的表。没有触发器,只有一个普通表和主索引。我已经在两个单独的浏览器选项卡中运行了这个网络应用程序代码:

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 只是为了看看发生了什么。所以我有 2 个问题 - 为什么 SCOPE_ 返回 NULL,为什么 @@IDENTITY 返回特定于范围的结果?

【问题讨论】:

    标签: sql-server identity-column


    【解决方案1】:

    不,@@IDENTITY 仍仅限于在同一会话中生成的标识值。见SCOPE_IDENTITY中的讨论:

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

    (已添加重点)

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

    【讨论】:

    • 啊会话.. 我明白了!完美的解释,非常感谢!但是你知道为什么 SCOPE_IDENTITY 会返回 NULL 吗?
    • SCOPE_IDENTITY 将在当前范围内没有INSERT 的表中返回NULL
    • 感谢 Damien,但确实有一个带有标识列的插入。我的意思是,否则@@IDENTITY 也不会返回任何东西。我错过了什么吗?
    • 这只是一个普通的INSERT,没有包裹在例如存储过程? (存储过程中的代码是不同的范围)
    • 啊再次......是的,它不在存储过程中,只是带有单个 sql 语句的命令对象。没有意识到存储过程被视为不同的范围。谢谢!
    【解决方案2】:

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

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

    SELECT SCOPE_IDENTITY()
    

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

    【讨论】:

      猜你喜欢
      • 2020-03-24
      • 1970-01-01
      • 2017-09-12
      • 2014-09-24
      • 1970-01-01
      • 2020-08-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多