【问题标题】:SQL Server 2008 R2 Recordset apears not createdSQL Server 2008 R2 记录集似乎未创建
【发布时间】:2017-01-02 17:51:19
【问题描述】:

环境:SQL Server Express 2008 R2、EW4、Windows XP SP3

这里有一些来自 ASPX 页面的重要程序语句。

conn=Server.CreateObject("ADODB.Connection")
conn.Open (connString)  -->  conn.State = True
sql1 = USE [my_db]; SELECT * FROM [dbo].[CustomerTable];
rs=Server.CreateObject("ADODB.Recordset") --> rs(create).State = False
rs.Open (sql1,conn)  -->  rs(open).State = False
conn.State = True
do until (rs.EOF)  // produces fatal exception

来自我的日志文件 (C:\Program Files\Microsoft SQL Server\MSSQL10_50.SQLEXPRESS\MSSQL\Log\ERRORLOG):

2017-01-02 12:31:06.33 服务器 SQL Server 网络接口 库无法注册服务主体名称 (SPN) SQL Server 服务。错误:0x54b,状态:3。未能 注册 SPN 可能会导致集成身份验证回退 到 NTLM 而不是 Kerberos。这是一条情报信息。 仅当 Kerberos 身份验证是 身份验证策略要求。

这些来自 Procmon.exe (SysInternalsSuite)

日期和时间:2017 年 1 月 2 日下午 12:21:33 事件类别:文件系统 操作:DeviceIoControl 结果:INVALID PARAMETER 路径:C:\Program 文件\Microsoft SQL Server\MSSQL10_50.SQLEXPRESS\ MSSQL\DATA\my_db.mdf TID:4972 持续时间:0.0000050 控制:IOCTL_MOUNTDEV_QUERY_DEVICE_NAME

日期和时间:2017 年 1 月 2 日下午 12:21:33 事件类别:文件系统 操作:CreateFile 结果:NAME INVALID 路径:C:\Program 文件\Microsoft SQL Server\MSSQL10_50.SQLEXPRESS\ MSSQL\DATA\my_db.mdf TID:4972 持续时间:0.0000107 所需访问:读取属性,同步处置:打开 选项:Synchronous IO Non-Alert、Open Reparse Point 属性:N 共享模式:读取、写入分配大小:不适用 冒充:servername\mainuser


关于解决SQL Server ERRORLOG中提到的SPN问题的早期努力,我找到了以下参考:

https://msdn.microsoft.com/en-us/library/ms191153(v=sql.110).aspx#Defaults

所以 Kerberos 用于远程连接。在这种情况下只有本地连接。所以本地不使用Kerberos 在这种情况下可能无关紧要。而是在本地使用 NTLM。

因此,在这种情况下,未注册 SPN 可能不是问题。

有一段时间,ERRORLOG 中提到的无法注册 SPN 和 Kerberos 身份验证警告似乎是唯一可以跟进的项目。这是那里列出的唯一重大错误(警告),并且有一段时间似乎是唯一的线索。

最初,SPN 问题似乎是由一些不适当的权限设置引起的。此外,许多网页似乎将 SPN 问题和无法运行查询归因于权限设置不足。该用户开始认为权限不足是他想象的记录集创建对象失败的根本原因。

具体来说,有一段时间,该用户认为 sql server 启动帐户无法创建记录集对象,因为它没有足够的权限来完成任务。此外,建议使用 Active Directory 授予 Read 和 WriteServicePrincipalName 权限(以启用远程连接的 Kerberos 身份验证)的 MSDN 网络文章进一步加深了用户的误解。最终,这种思路被证明是不正确的,因为计算机是独立的(未联网),并且不是服务器操作系统不能有 AD DC(本地),没有任何远程数据库连接并且不需要 Kerberos 身份验证用于远程连接。

所以最终判断sql server ERRORLOG中的SPN和Kerberos警告在这种情况下不存在问题。但这部分调查耗费了大量的时间和精力,非常混乱。

虽然,关于权限,将 sql server 启动帐户登录类型从本地服务设置(更改)为本地系统(更高权限的帐户)似乎确实有所改善。


请接受我对您(和其他人)为我的计划提供的帮助和努力的感谢。我怀疑您可能拥有比我可能获得的更多的 sql server 经验,因此值得尊重。但我的目标是不同的,让网站完全启动并运行。我正在认真尝试听从您的建议。

总的来说,对于这个程序,它很重要,因为在修复之前没有可用的数据库,没有可用的网站,工程公司也无法打开大门。

关于这个程序,我严重怀疑实际上只有一个(主要)持久性问题(后来发现是格式错误的查询字符串)。最初看起来是数据库连接或权限问题导致创建记录集对象失败(rs.State=0),但事实证明这是不正确的。 db 连接被证明是足够的,并且 rs.State=0(对于创建 rs 对象)不是错误,更像是天生的零记录消息。最初的 rs.State=0(用于 rs 创建对象)被误解并被证明非常混乱。

更令人困惑的是,rs.State 实际上返回的是一个枚举值(本质上是一个整数)而不是一个布尔值(例如代码 sn-p 视图窗口中显示的 False)。此处显示了意外的数据类型不匹配(意外的非法转换)。所以原来的代码 sn-p 视图窗口在这种情况下并不完全正确。

当程序最终正确运行时 rs(create).State=0 和 rs(open).State=1,这不是预期的结果。事实上,rs(create).State 和 rs(open).State 应该都等于 1 的最初期望被证明是不正确的。这位用户仔细观察了 rs(create).State 方法的对象属性值被证明是一个无用的职业。 (它并没有真正帮助。)

当 "USE [my_db]; " 部分从 sql 查询字符串中删除后,数据库开始被正确查询并且 RS.State=1(对于 rs.Open)。到目前为止,“USE [my_db];”杀死了每个查询。事情开始澄清,然后很明显存在(或曾经)三重数据库连接规范,通常(或总是)有害。连接字符串中的两个,带有 AttachDBFilename 参数和 Database 参数。 sql 查询字符串中的第三个带有“USE [my_db];”。尽管所有三个条目都是相同且正确的(对人类而言),三个数据库连接无疑会导致一些软件问题(因为指定过多)。使用 Procmon.exe (SysInternalsSuite) 进行的进一步测试显示了与 AttachDBFilename 参数相关的错误,并且在单独使用时与(连接字符串)数据库参数相关的错误为零。因此选择了 Database 参数在连接字符串中单独使用。

关于 Multiple Active Result Sets (MARS) 属性连接字符串参数,以下 MSDN 网络文章说它最初默认禁用。显然,它是一个高级数据库功能,涉及几个高级问题,同步、异步、缓存、多个批处理命令会话。虽然 MARS 功能很有价值,但人们认为它应该被禁用,直到用户变得足够先进,可以在代码中正确处理它。所以不建议db初学者使用这个MARS连接参数。 https://msdn.microsoft.com/en-us/library/h32h3abf(v=vs.110).aspx

通常与 MARS 一起使用,“DataTypeCompatibility=80;”参数将 db 数据类型限制为 2005 集。这似乎是不必要和不利的。除非使用 MARS,否则不建议使用此参数。 https://msdn.microsoft.com/en-us/library/ms131002(v=sql.110).aspx

最后一个等效键值对:“Integrated Security=SSPI”等于“Trusted_Connection=yes”。
所以选择了一个以避免冗余。

一条评论说:“在这里查看有关如何创建正确连接字符串的信息:https://social.technet.microsoft.com/wiki/contents/articles/1409.how-to-create-a-sql-connection-string-for-an-application-udl-file.aspx。”我确实觉得这个 UDL 过程很有用,因为它提供了系统确认正确的提供者(和其他一些东西)应该是什么。即便如此,我最终还是使用了自定义连接字符串。

关于确认连接字符串,确切的结果是:

[oledb] ;此行之后的所有内容都是 OLE DB 初始化字符串
Provider=SQLNCLI10.1;Integrated Security=SSPI;Persist Security Info=False;User ID="";Initial Catalog=my_db;Data Source=serverName\SQLEXPRESS;Initial File Name="";Server SPN=""


我要特别感谢尼克。他费了很大力气,一直陪在我身边,直到成功解决。他关于删除“USE [my_db];”的评论直接导致了修复。完成后,最简单的测试 sql 查询实际上运行正确。所有其他错误都像纸牌屋一样消失了(一件好事)。所以我猜他找到了我问题的根源。衷心感谢尼克。

【问题讨论】:

  • 数据库处于什么状态?您链接的知识库文章包含“在撰写本文时,Microsoft 不认为这些错误消息会阻止数据库启动。”
  • 可能是愚蠢的问题,但这个文件存在吗? 'C:\Program Files\Microsoft SQL Server\MSSQL10_50.SQLEXPRESS\MSSQL\DATA\my_db.mdf'
  • 这是一个重要的业务应用程序,但我遇到了困难。因此,如果有助于解决问题,毫无疑问是愚蠢的。出于安全原因,在帖子中更改了数据库的名称。它在本地确实存在,我会定期在 SSMS 中打开它以进行测试和修改。
  • 这似乎是由于您的服务帐户无法在您的 DNS 上注册服务器名称。此处概述了问题的关键“SQL Server 网络接口库无法为 SQL Server 服务注册服务主体名称 (SPN)。”不要为您的服务帐户使用默认帐户!
  • 你的代码真的会报错吗?这里的实际问题是什么?我实际上并没有在所有这些词中看到任何错误或问题。

标签: sql-server sql-server-2008r2-express


【解决方案1】:

这是部分理论,可能不完全正确,但这是我的理解。

似乎Recordset.Open 没有返回记录时,它返回一个state=0

当您运行此查询时:

USE [my_db]; SELECT * FROM [dbo].[CustomerTable];

它从第一条语句返回第一个记录集。在这种情况下,第一个语句是

USE [my_db];

不返回任何记录

所以在打开的部分不会抛出任何错误,因为它已经完美运行了

检查rs.EOF时会抛出错误,因为记录集已关闭(因为语句没有返回任何记录或列)

如果您深入了解致命异常,您会看到类似的错误。

我怀疑如果你从一个空表中选择结果会有点不同,即一个没有记录的打开记录集。

这与编写存储过程时的SET NOCOUNT ON 要求非常相似

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多