这是一个最小的重现示例。
数据库:
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
预期结果: The Debug.Print
line 向调试窗口输出一个整数。
实际结果: The Debug.Print
线路输出Null
到调试窗口。
Notes:
- 一旦我删除标记为的行
[X]
,代码按预期工作(最后插入的标识值被写入调试窗口)。
-
这是一个最小的重现示例: I know服务器端游标是“邪恶的”。我know在这种特殊情况下添加
SELECT SCOPE_IDENTITY()
到 INSERT 批处理是获取新插入的 ID 的正确方法。这只是一个用尽可能少的代码重现问题的最小示例。我在修改遗留代码时偶然发现了这个问题。
- 使用 SQL Server Native Client 11.0 和“经典”MDAC SQL Server ODBC 驱动程序进行了测试。使用 SQL Server 2005 和 2012 进行测试。没有什么区别。
我的问题:这是设计使然,还是我偶然发现了 SQL Server 错误?如果是前者,它记录在哪里?
编辑:将两个选项(带和不带 [X])与 SQL Server Profiler 跟踪进行比较,有一个显着差异:当包含 [X] 行时,连接显然被删除并重新打开(Audit Logout
- Audit Login
) 之间cmd.Execute
and rs2.Open
。我想这可以解释为什么@@IDENTITY
不再有效。
这就留下了以下问题:为什么 ADO(或 SQLNCLI11 驱动程序?)在一种情况下关闭并重新打开连接,而在另一种情况下则不然?这在哪里记录?
MARS 是默认行为的更好替代方案,它实际上允许多个记录集。
发生的情况是:
-
SELECT 1
充当连接的活动记录集并保持打开状态
- 当你执行
insert
提供程序知道它有一个活动记录集,并尝试通过创建新连接来执行语句而不干扰任何内容来提供帮助
- 这个临时连接执行
insert
然后通过执行锁定来整理 - 销毁与其关联的状态
-
select @@identity
再次使用临时连接,其中@@identity
因为前面的语句超出了范围,因此NULL
.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)