服务器端仅向前游标中断@@ IDENTITY

时间:2018-01-29 10:53:17

标签: sql-server vba oledb ado 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行向调试窗口输出一个整数。

实际结果: Debug.Print行输出Null到调试窗口。

备注:

  • 一旦删除标记为[X]的行,代码就会按预期工作(最后插入的标识值将写入调试窗口)。
  • 这是一个最小的repro示例:我知道服务器端游标是" evil"。我知道在这种特殊情况下,将SELECT SCOPE_IDENTITY()添加到INSERT批处理是获取新插入ID的正确方法。这只是用尽可能少的代码重现问题的最小例子。我在修改遗留代码时偶然发现了这个问题。
  • 使用SQL Server Native Client 11.0和" classic"进行测试MDAC SQL Server ODBC驱动程序。使用SQL Server 2005和2012进行测试。没有任何区别。

我的问题:这是设计上的行为,还是偶然发现了SQL Server错误?如果是前者,它在哪里记录?

编辑:将两个选项(有和没有[X])与SQL Server Profiler跟踪进行比较,有一个显着的区别:当包含[X]行时,连接显然被删除并重新打开({{1 } { - {1}}在Audit LogoutAudit Login之间。我想这可以解释为什么cmd.Execute不再有效。

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

2 个答案:

答案 0 :(得分:2)

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

会发生什么:

  1. SELECT 1充当连接的活动记录集&仍然开放
  2. 当您执行insert时,提供程序知道它有一个活动记录集并尝试通过创建新连接来执行该语句而不会干扰任何内容
  3. 这个短暂的连接执行insert然后通过执行注销来破坏 - 与之相关的销毁状态
  4. select @@identity再次使用短暂连接,其中前一个语句的@@identity超出范围,因此NULL
  5. enter image description here

答案 1 :(得分:0)

我注意到你在同一个连接上做两次选择。您是否尝试过启用"多个活动结果集"通过添加" MultipleActiveResultSets = True"你的连接字符串?

Enabling Multiple Active Result Sets on MSDN