经典 ASP VBScript 需要替换 MyConn.Execute( 查询 )

Classic ASP VBScript need dropin replacement for MyConn.Execute( query )

我在 ASP VBScript 上有一个站点 运行,原始代码从不关闭数据库连接。它作为 "startup" 的一部分为任何给定页面打开连接,然后执行它所做的一切并停止——但从不显式关闭连接。现在这会导致 Web 服务器级别崩溃的问题——可能是由于缺乏垃圾收集。

所以我想创建一个函数来替代整个站点中所有 MyConn.Execute( sqlQuery ) 命令。我找到了一些不错的候选人,但其中 none 似乎很管用。最有希望的似乎是下面的代码,但是当我尝试实际使用记录集时 returned 我得到一个错误。

Function GetRS(strSQL)
  'this function returns a disconnected RS

  'Set some constants
  Const adOpenStatic = 3    
  Const adUseClient = 3
  Const adLockBatchOptimistic = 4 

  'Declare our variables
  Dim oConn
  Dim strSQL
  Dim oRS

  'Open a connection
  Set oConn = Server.CreateObject("ADODB.Connection")
  oConn.ConnectionString = "Driver={MySQL ODBC 5.3 Unicode Driver};Server=localhost;User=foo;Password=bar;Database=baz"
  oConn.Open

  'Create the Recordset object
  Set oRS = Server.CreateObject("ADODB.Recordset")
  oRS.CursorLocation = adUseClient

  'Populate the Recordset object with a SQL query
  oRS.Open strSQL, oConn, adOpenStatic, adLockBatchOptimistic

  'Disconnect the Recordset
  Set oRS.ActiveConnection = Nothing

  'Return the Recordset
  Set GetRS = oRS

  'Clean up...
  oConn.Close
  oRS.Close
  Set oConn = Nothing
  Set oRS = Nothing
End Function

'call the function
strSQL = "SELECT * FROM Authors"   
set RS = GetRS(strSQL)

(来源:http://www.4guysfromrolla.com/webtech/080101-1.shtml

这是我的测试代码:

Set rs = GetRS( "SELECT `first_name` FROM `users` WHERE `id`=123" )
x = rs( "first_name" )
response.write x

我收到错误:

ADODB.Recordset error '800a0cc1'

Item cannot be found in the collection corresponding to the requested name or ordinal.

/test.asp, line 25 

使用序数 -- rs(0) -- returns 同样的错误。

对我来说看起来像一个空记录集,但它是一个合法的查询 return 一条记录。

有谁知道为什么这不起作用,或者可以向我指出可以完成这项工作的其他代码? (尤其是 4guys 文章缺少的实际使用示例。)

我的理解是 Recordset 与数据源相关联。当您执行查询时,默认情况下,客户端(您的程序)不会获取查询的全部内容,而是会等到您实际请求数据。这样,您可以选择特定的页面大小、页面偏移量等,以有效地 select 数据库中的行,而无需通过网络传输可能的数百万行。

这样做的副作用是,如果关闭数据库连接,您将无法再使用 Recordset。在完成连接之前,您必须保持连接打开。同样,关闭 Recordset 本身将阻止您进一步与它交互。

您有两个选择:在关闭之前将数据从 Recordset 复制到您自己的 variables/arrays,或者使用不同的技术来管理您的连接。我这里说后一种选择。

有一种技术可以让您打开数据库连接一次,并确保它在终止时由 VBScript 正确关闭。

Class DbConnectionManager
    Private Sub Class_Initialize()
        Set oConn = Server.CreateObject("ADODB.Connection")
        oConn.ConnectionString = "Driver={MySQL ODBC 5.3 Unicode Driver};Server=localhost;User=foo;Password=bar;Database=baz"
        oConn.Open
    End Sub

    Private Sub Class_Terminate()
        oConn.Close
    End Sub
End Class

Dim connMgr : Set connMgr = New DbConnectionManager

此代码片段未经测试,但一般原则是您通过定义 class 并创建它的实例来启动您的程序。当一个 class 实例被创建时, Class_Initialize 被调用,当你的程序结束时(或者实例被删除并被垃圾收集),然后 Class_Terminate 将被调用。这意味着 oConn.Close 应始终在程序结束之前调用,即使出现错误也是如此。

这是 class 工作原理的一个非常基本的示例,但您实际上可以进一步扩展 class 并将您的执行函数插入 class 本身以封装数据库连接细节,便于维护。如果您还没有在 VBScript 中使用过 classes,但您对面向对象编程的工作原理有基本的了解,我强烈建议您尝试一下。

额外奖励:看起来您正在传递原始 SQL 字符串。为避免 SQL 注入漏洞,请勿动态构建 SQL 查询。相反,请使用 ADO 和参数,这样任何用户创建的内容都可以安全地传递到查询中而没有安全风险。 How do I run a parameterized SQL query in classic ASP? And is it secure? W3Schools 也有一节介绍如何使用 ADO。