Asp classic 什么';这个ASP递归函数有什么问题?

Asp classic 什么';这个ASP递归函数有什么问题?,asp-classic,vbscript,ado,Asp Classic,Vbscript,Ado,当我调用这个函数时,只要我不再尝试递归调用该函数,一切都会正常工作。换句话说,如果我取消注释该行: GetChilds rsData("AcctID"), intLevel + 1 然后函数中断 <% Function GetChilds(ParentID, intLevel) Set rsData= Server.CreateObject("ADODB.Recordset") sSQL = "SELECT AcctID, ParentID FR

当我调用这个函数时,只要我不再尝试递归调用该函数,一切都会正常工作。换句话说,如果我取消注释该行:

GetChilds rsData("AcctID"), intLevel + 1 
然后函数中断

<%
    Function GetChilds(ParentID, intLevel)
        Set rsData= Server.CreateObject("ADODB.Recordset")
        sSQL = "SELECT AcctID, ParentID FROM Accounts WHERE ParentID='" & ParentID &"'"
        rsData.Open sSQL, conDB, adOpenKeyset, adLockOptimistic
        If IsRSEmpty(rsData) Then
            Response.Write("Empty")
        Else
            Do Until rsData.EOF
                Response.Write rsData("AcctID") & "<br />"
                'GetChilds rsData("AcctID"), intLevel + 1 
                rsData.MoveNext
            Loop
        End If
        rsData.close: set rsData = nothing
    End Function

    Call GetChilds(1,0)
%>
我不确定是什么导致了这些问题。我理解这可能是由几个因素造成的

  • 不关闭连接并尝试重新打开同一连接
  • 到数据库的多个并发连接
  • 数据库内容如下:

    AcctID | ParentID
    1        Null
    2        1
    3        1
    4        2
    5        2
    6        3
    7        4
    
    AcctID | ParentID
    1        Null
    2        1
    3        1
    4        2
    5        2
    6        3
    7        4
    
    Function GetChilds(ParentID, intLevel)
            'Open my Database Connection and Query the current Parent ID
            Set rsData= Server.CreateObject("ADODB.Recordset")
            sSQL = "SELECT AcctID, ParentID FROM Accounts WHERE ParentID='" & ParentID &"'"
            rsData.Open sSQL, conDB, adOpenKeyset, adLockOptimistic
            'If the Record Set is not empty continue
            If Not IsRSEmpty(rsData) Then
                Dim myAccts()
                ReDim myAccts(rsData.RecordCount)
                Dim i
                i = 0
                Do Until rsData.EOF
                    Response.Write "Account ID: " & rsData("AcctID") & " ParentID: " & rsData("ParentID") & "<br />"
                    'Add the Childs of the current Parent ID to an array.
                    myAccts(i) = rsData("AcctID")
                    i = i + 1
                    rsData.MoveNext
                Loop
                'Close the SQL connection and get it ready for reopen. (I know not the best way but hey I am just learning this stuff)
                rsData.close: set rsData = nothing
                'For each Child found in the previous query, now lets get their childs.
                For i = 0 To UBound(myAccts)
                    Call GetChilds(myAccts(i), intLevel + 1)
                Next
            End If
        End Function
    
        Call GetChilds(1,0)
    
    我的想法是,我可以有一个主帐户和子帐户,这些子帐户可以有自己的子帐户。最终将有另一个ParentID为Null的主帐户,它将有自己的孩子。考虑到这一点,我的做法是否正确

    谢谢你的快速回复


    谢谢大家,

    除通常的错误外:

    Error Type: (0x80020009) Exception occurred.
    
    错误类型:(0x80020009)异常 发生了

    我不确定是什么导致了这些问题。我理解这可能是由几个因素造成的

  • 不关闭连接并尝试重新打开同一连接
  • 到数据库的多个并发连接
  • 数据库内容如下:

    AcctID | ParentID
    1        Null
    2        1
    3        1
    4        2
    5        2
    6        3
    7        4
    
    AcctID | ParentID
    1        Null
    2        1
    3        1
    4        2
    5        2
    6        3
    7        4
    
    Function GetChilds(ParentID, intLevel)
            'Open my Database Connection and Query the current Parent ID
            Set rsData= Server.CreateObject("ADODB.Recordset")
            sSQL = "SELECT AcctID, ParentID FROM Accounts WHERE ParentID='" & ParentID &"'"
            rsData.Open sSQL, conDB, adOpenKeyset, adLockOptimistic
            'If the Record Set is not empty continue
            If Not IsRSEmpty(rsData) Then
                Dim myAccts()
                ReDim myAccts(rsData.RecordCount)
                Dim i
                i = 0
                Do Until rsData.EOF
                    Response.Write "Account ID: " & rsData("AcctID") & " ParentID: " & rsData("ParentID") & "<br />"
                    'Add the Childs of the current Parent ID to an array.
                    myAccts(i) = rsData("AcctID")
                    i = i + 1
                    rsData.MoveNext
                Loop
                'Close the SQL connection and get it ready for reopen. (I know not the best way but hey I am just learning this stuff)
                rsData.close: set rsData = nothing
                'For each Child found in the previous query, now lets get their childs.
                For i = 0 To UBound(myAccts)
                    Call GetChilds(myAccts(i), intLevel + 1)
                Next
            End If
        End Function
    
        Call GetChilds(1,0)
    
    我的想法是,我可以有一个主帐户和子帐户,这些子帐户可以有自己的子帐户。最终将有另一个ParentID为Null的主帐户,它将有自己的孩子。考虑到这一点,我的做法是否正确


    感谢您的快速响应。

    尝试在函数定义中使用DIM语句将变量声明为本地变量:

    Function GetChilds(ParentID, intLevel)
    Dim rsData, sSQL
    Set ...
    
    编辑:好的,我试着更明确一些

    我的理解是,由于rsData不是由DIM声明的,所以它不是局部变量,而是全局变量。因此,如果循环执行WHILE语句,则会到达最内部的rsData记录集的.Eof。您从递归函数调用返回,下一步再次是rsData.MoveNext,它失败了


    如果rsData确实是本地的,请纠正我。

    SQL连接不足

    您要处理的层太多(客户机的Response.Write、服务器的ASP和数据库),因此出现问题也就不足为奇了

    也许您可以发布一些有关错误的详细信息?

    它是如何中断的


    我的猜测是,经过一定数量的递归之后,您可能会出现堆栈溢出(讽刺的是),因为您没有分配太多的记录集。

    如果不详细描述它是如何中断的,很难说,但是您没有将intLevel用于任何用途。

    看起来它失败了,因为您的连接仍在忙着为上一次呼叫的记录集提供服务

    一种选择是为每个呼叫使用新的连接。存在的危险是,如果递归次数过多,您将很快耗尽连接

    另一种选择是将每个记录集的内容读入一个断开连接的集合:(字典、数组等),以便您可以立即关闭连接。然后迭代断开连接的集合

    如果您使用的是SQLServer2005或更高版本,还有一个更好的选择。可以使用CTE(公共表表达式)编写递归sql查询。然后,您可以将所有内容移动到数据库,只需执行一个查询

    其他注意事项:
    ID字段通常是
    int
    s,因此不应该将它们封装在sql字符串中的“字符”中

    最后,这段代码可能还可以,因为我怀疑用户是否可以直接输入id号。但是,使用的动态sql技术非常危险,通常应该避免使用。改为使用查询参数以防止sql注入


    我不太担心什么都不用
    intLevel
    。从代码上看,这显然是早期版本,以后可以使用intLevel来确定缩进或在设置元素样式时使用的类名。

    在每次调用中,您打开一个到数据库的新连接,而在打开一个新连接之前,您不会关闭它。

    这并不是递归问题的实际解决方案,但是,对于您来说,编写一个以分层格式返回所有信息的SQL语句可能比对数据库进行递归调用更好


    但仔细想想,这可能是因为您有太多的并发数据库连接。您会不断地打开,但在退出递归循环之前不会开始关闭。

    如果您需要这样的递归,我会亲自将递归放入存储过程中,并在数据库端处理该处理,以避免打开多个连接。如果您使用的是mssql2005,请查看称为公共表表达式(CTE)的内容,它们使递归变得简单。还有其他方法可以实现与其他RDBMS的递归。

    基于这些建议,当我找到一个很好的关于如何实现的教程时,我会尝试将查询移动到CTE(公共表表达式)中。现在,作为一个快速而肮脏的修复,我已将代码更改如下:

    AcctID | ParentID
    1        Null
    2        1
    3        1
    4        2
    5        2
    6        3
    7        4
    
    AcctID | ParentID
    1        Null
    2        1
    3        1
    4        2
    5        2
    6        3
    7        4
    
    Function GetChilds(ParentID, intLevel)
            'Open my Database Connection and Query the current Parent ID
            Set rsData= Server.CreateObject("ADODB.Recordset")
            sSQL = "SELECT AcctID, ParentID FROM Accounts WHERE ParentID='" & ParentID &"'"
            rsData.Open sSQL, conDB, adOpenKeyset, adLockOptimistic
            'If the Record Set is not empty continue
            If Not IsRSEmpty(rsData) Then
                Dim myAccts()
                ReDim myAccts(rsData.RecordCount)
                Dim i
                i = 0
                Do Until rsData.EOF
                    Response.Write "Account ID: " & rsData("AcctID") & " ParentID: " & rsData("ParentID") & "<br />"
                    'Add the Childs of the current Parent ID to an array.
                    myAccts(i) = rsData("AcctID")
                    i = i + 1
                    rsData.MoveNext
                Loop
                'Close the SQL connection and get it ready for reopen. (I know not the best way but hey I am just learning this stuff)
                rsData.close: set rsData = nothing
                'For each Child found in the previous query, now lets get their childs.
                For i = 0 To UBound(myAccts)
                    Call GetChilds(myAccts(i), intLevel + 1)
                Next
            End If
        End Function
    
        Call GetChilds(1,0)
    
    函数GetChilds(ParentID,intLevel) '打开我的数据库连接并查询当前父ID Set rsData=Server.CreateObject(“ADODB.Recordset”) sSQL=“从ParentID=”&ParentID&“的帐户中选择帐户,ParentID” 打开sSQL、conDB、adOpenKeyset、ADLOCK '如果记录集不是空的,请继续 如果不是ISSEMPTY(rsData),则 Dim myAccts() 重拨myAccts(rsData.RecordCount) 昏暗的我 i=0 直到rsData.EOF为止 响应。写入“帐户ID:&rsData(“AcctID”)和“家长ID:&rsData(“家长ID”)和”
    '将当前父ID的子项添加到数组中。 myAccts(i)=r