服务器端只进游标中断@@IDENTITY

Server-side forward-only cursor breaks @@IDENTITY

这是一个最小的重现示例。

数据库:

CREATE TABLE temp (x int IDENTITY(1, 1), y int);

代码(使用VBA和ADO):

Public Sub repro()
    Dim cn As New Connection
    Dim rs1 As New Recordset
    Dim cmd As New Command
    Dim rs2 As New Recordset

    cn.Open "Provider=SQLNCLI11;Server=myServer;Database=myDatabase;Trusted_Connection=Yes"

    rs1.Open "SELECT 1", cn, adOpenForwardOnly      ' [X] '

    cmd.ActiveConnection = cn
    cmd.CommandText = "INSERT INTO temp (y) VALUES (1) "
    cmd.Execute

    rs2.Open "SELECT @@IDENTITY", cn, adOpenStatic
    Debug.Print rs2(0).value

    rs2.Close
    rs1.Close                                       ' [X] '
    cn.Close
End Sub

预期结果: Debug.Print 行向调试 window.

输出一个整数

实际结果: Debug.Print 行输出 Null 到调试 window.

备注:

我的问题:这是设计使然,还是我偶然发现了 SQL 服务器错误?如果是前者,它在哪里记录?


编辑:将两个选项(有和没有 [X])与 SQL Server Profiler 跟踪进行比较,有一个显着差异:当包含 [X] 行时,连接显然已断开并在 cmd.Executers2.Open 之间重新开放(Audit Logout - Audit Login)。我想这解释了为什么 @@IDENTITY 不再有效。

这留下了以下问题:为什么 ADO(或 SQLNCLI11 驱动程序?)在一种情况下关闭并重新打开连接,而在另一种情况下却没有?这记录在哪里?

我注意到您在同一个连接上进行了两次选择。您是否尝试通过将 "MultipleActiveResultSets=True" 添加到您的连接字符串来启用 "Multiple Active Result Sets"?

Enabling Multiple Active Result Sets on MSDN

MARS 是默认行为的更好替代方法,默认行为实际上允许多个记录集。

发生的事情是:

  1. SELECT 1 充当连接的活动记录集并保持打开状态
  2. 当您随后执行 insert 时,提供程序知道它有一个活动记录集,并试图通过创建一个新连接来提供帮助来执行该语句而不干扰任何东西
  3. 此临时连接执行 insert 然后通过执行注销进行清理 - 销毁与其关联的状态
  4. select @@identity 再次使用临时连接,其中前一个语句的 @@identity 超出范围,因此 NULL.