2008-11-18 50 views
2

當我調用這個函數時,一切正常,只要我不試圖遞歸調用函數。換句話說,如果我取消註釋行:這個ASP遞歸函數有什麼問題?

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) 
%> 

*反饋

謝謝大家編輯後,

比一般的錯誤其它:

Error Type: (0x80020009) Exception occurred. 

我不知道是什麼導致的問題。我明白這可能是由於幾個因素。

  1. 未關閉連接並嘗試重新打開相同的連接。
  2. 對數據庫的許多併發連接。

數據庫內容如下:

AcctID | ParentID 
1  Null 
2  1 
3  1 
4  2 
5  2 
6  3 
7  4 

的想法是,這樣我可以有子帳戶主賬戶,而這些子帳戶都可以擁有自己的子帳戶。最終會有另一個MasterID賬戶,其ParentID爲Null,將擁有自己的孩子。考慮到這一點,我是否以正確的方式開展這項工作?

感謝您的快速回復。


謝謝大家,

比一般的錯誤其它:

Error Type: (0x80020009) Exception occurred.

我不知道是什麼導致的問題。我明白這可能是由於幾個因素。

  1. 未關閉連接並嘗試重新打開相同的連接。
  2. 對數據庫的許多併發連接。

數據庫內容如下:

AcctID | ParentID 
1  Null 
2  1 
3  1 
4  2 
5  2 
6  3 
7  4 

的想法是,這樣我可以有子帳戶主賬戶,而這些子帳戶都可以擁有自己的子帳戶。最終會有另一個MasterID賬戶,其ParentID爲Null,將擁有自己的孩子。考慮到這一點,我是否以正確的方式開展這項工作?

感謝您的快速回復。

+0

您是否收到錯誤消息? – 2008-11-18 19:48:28

+0

函數卡住或返回錯誤?你有沒有檢查你的數據循環? – 2008-11-18 19:57:04

回答

2

看起來像失敗了,因爲您的連接仍然忙於服務前一次調用的RecordSet。

一種選擇是爲每個呼叫使用全新連接。如果你遞歸太多次,那麼你很快就會失去聯繫。

另一種選擇是將每個RecordSet的內容讀入一個斷開的集合:(Dictionary,Array等),以便您可以立即關閉連接。然後遍歷斷開連接的集合。

如果您使用SQL Server 2005或更高版本,則有更好的選擇。您可以使用CTE(公用表表達式)編寫遞歸sql查詢。然後,您可以將所有內容移動到數據庫,並且只需執行一個查詢。

其他注意事項:
ID字段通常是int s,所以您不應將它們包含在sql字符串中的字符中。

最後,這段代碼可能沒問題,因爲我懷疑用戶是否被允許直接輸入一個id號。但是,所使用的動態sql技術非常危險,通常應該避免。使用查詢參數來防止sql注入。

我並不太擔心不使用intLevel做任何事情。看看代碼,這顯然是一個早期版本,intLevel稍後可以用來確定類似縮進或樣式化元素時使用的類名稱。

0

嘗試使用函數定義中的DIM聲明,宣佈該變量爲本地:

Function GetChilds(ParentID, intLevel) 
Dim rsData, sSQL 
Set ... 

編輯:好吧,我儘量做到更加明確。

我的理解是,由於rsData沒有被DIM聲明,所以它不是局部變量,而是全局變量。因此,如果循環訪問WHILE語句,則會到達最內層rsData記錄集的.Eof。您從遞歸函數調用返回,並且下一步再次是失敗的rsData.MoveNext。

如果rsData確實是本地的,請糾正我。

1

用完SQL連接?

你正在處理那麼多的層(客戶端的Response.Write,服務器的ASP和數據庫),這並不奇怪有問題。

也許你可以發佈一些關於錯誤的細節?

+0

他不會每次都創建一個新的連接 - 他試圖對多個記錄集使用相同的連接,而傳統的asp不支持IIRC。但它是在正確的軌道上。 – 2008-11-18 19:57:18

+0

我認爲ADO支持連接池,所以他沒有用完連接。這是我的來源http://www.15seconds.com/issue/970531.htm – MrChrister 2008-11-18 20:07:33

0

它是如何突破的?

我的猜測是,經過一定數量的遞歸後,你可能會得到堆棧溢出(諷刺),因爲你沒有分配太多的RecordSet。

1

很難說,沒有關於它如何破壞的更多描述,但是你沒有使用intLevel來做任何事情。

0

在每次調用中,您都會打開一個到數據庫的新連接,並且在打開一個新連接之前不要關閉它。

0

不是說這實際上是遞歸問題的解決方案,但是您可能更好地制定一個以分層格式返回所有信息的SQL語句,而不是對數據庫進行遞歸調用。

想想看,雖然它可能是因爲你有太多的併發數據庫連接。你不斷打開,但不會開始關閉,直到你退出你的遞歸循環。

0

如果你需要這樣的遞歸,我會親自把遞歸存儲到存儲過程中,並處理數據庫端的處理,以避免打開多個連接。如果你使用mssql2005查看一些叫做Common Table Expressions(CTE)的東西,它們使遞歸變得容易。還有其他方法可以用其他RDBMS實現遞歸。

0

基於這些消耗,我會嘗試將查詢移動到CTE(公用表表達式),當我找到一個很好的教程,瞭解如何做到這一點。

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) 
0

我有相同的情況下工作代碼:現在作爲一個快速和骯髒的修復,如下我已經改變了代碼。

我使用的是客戶方光標

... 
rsData.CursorLocation = adUseClient 
rsData.Open sSQL, conDB, adOpenKeyset, adLockOptimistic 
rsData.ActiveConnectcion = Nothing 
... 

在其他答覆中指出,這是不是很有效,我只在一個管理界面,代碼很少被調用和速度不是關鍵使用它。

我不會在常規網頁中使用這樣的遞歸過程。 可以重寫代碼以從數據庫獲取一次調用中的所有數據,也可以調用一次並將其保存到本地數組,並將數組保存到應用程序變量中。