【问题标题】:InvalidOperationException: Timeout - recursive DB accessInvalidOperationException:超时 - 递归数据库访问
【发布时间】:2013-03-31 16:47:51
【问题描述】:

目前,我的一个 Web 应用程序存在严重问题,每天大约会出现六次超时异常。

错误:“在从池中获取连接之前已经过了超时时间。这可能是因为所有池连接都在使用中并且达到了最大池大小”。

经过大量谷歌搜索后,我发现问题与未关闭的连接有关。所以我检查了所有以任何方式访问数据库的函数,直到我偶然发现了这个:

    Private Sub getOrgas(ByVal orgID As String)
        Dim Id = orgID
        orgColl.Add(Id)
        While (Not IsNothing(Id))
            Dim conn = Database.DbWrapper.GetConnection(1, Integration.Mandanten.DatabaseType.AddonSQL)
            Dim paras As New HashSet(Of System.Data.Common.DbParameter)
            Dim orgatmp As String
            paras.Add(New SqlClient.SqlParameter("@Id", orgID))
            Dim dr = Database.DbWrapper.GetDataReaderFromStoredProcedure("stp_Orgas_Get", paras, conn)
            While dr.Read
                If Not valueInColl(CStr(dr(0))) Then
                    orgatmp = dr(0).ToString
                    orgColl.Add(orgatmp)
                    getOrgas(orgatmp)
                End If
            End While
            dr.Close()
            conn.Close()
            Id = Nothing
        End While
    End Sub

正如你所看到的,这个函数执行一个存储过程,并通过一个while循环运行结果,如果特定条件-valueInColl-,它会再次调用该函数。现在以这种方式,可能有 20 个或更多打开的连接。它与通过 GetDataReaderFromStoredProcedure 设置为 600 的超时值无关,这实际上应该足够了。可以肯定的是,我将价值翻了一番,并将在今晚推出。我会在第二天看看这是否有帮助。 我认为问题在于同时打开的连接太多,因为递归函数,但我不知道如何解决这个问题。

我找不到任何关于如何编辑最大连接数的信息。我什至不完全确定必须在哪里设置它。是 IIS、数据库本身还是编程参数 (VB.net/ASP.NET)。 如果你们能在这里帮助我,那就太好了。

[编辑] 好的,有人想重用连接变量,但这不起作用,因为数据读取器仍在运行。只要它没有关闭,我就不能以任何方式重用连接,也不能关闭数据读取器,因为这样做可能会丢失数据。 dr.read 的 while 循环还没有结束,但.. 另一方面,我删除了(几乎没用的)外部 while 并使用了一个 If 子句作为交换:

Private Sub getOrgas(ByVal orgID As String, ByVal con As DbConnection)
    Dim Id = orgID
    Dim conn As DbConnection
    Dim tmpOrga As String
    orgColl.Add(Id)
    If Not IsNothing(Id) Then
        If IsNothing(con) Then
            conn = Database.DbWrapper.GetConnection(1, Integration.Mandanten.DatabaseType.AddonSQL)
        Else
            conn = con
        End If
        Dim paras As New HashSet(Of System.Data.Common.DbParameter)
        paras.Add(New SqlClient.SqlParameter("@Id", orgID))
        Dim dr = Database.DbWrapper.GetDataReaderFromStoredProcedure("stp_Orgas_Get", paras, conn)
        While dr.Read
            If Not valueInColl(CStr(dr(0))) Then
                tmpOrga = dr(0).ToString
                orgColl.Add(tmpOrga)
                getOrgas(tmpOrga, conn)
            End If
        End While
        dr.close()
        conn.Close()
        Id = Nothing
    End If
End Sub

【问题讨论】:

    标签: asp.net sql recursion timeout


    【解决方案1】:

    你有什么理由不能重构东西,让每个递归都使用相同的数据库连接?

    我不是 VB 编码员,但我会按以下方式处理它

    1. 更改 getOrgas() 以采用默认为“无”的连接参数。
    2. Dim conn 行更改为if IsNothing(connParameter) conn = GetConnection() else conn := connParameter;
    3. 将递归行更改为getOrgas(orgatmp, conn);
    4. 从中测试出 F%%%%。

    我刚刚注意到外部的While 循环。只是为了迷惑你吗?它会执行多少次? ...


    我确实想知道数据阅读器 - 试试这个 - 我看到你的数据阅读器需要在你递归之前关闭,所以关闭它。

    在伪代码中-

    dim locallist = new list();
    while dr.read
    {
      LocalList.Add dr.thing;
    }
    dr.close;
    
    foreach(thing in locallist)
    {
       if Not ValueInColl(thing) Then
         CallYourFunctionTRecursively()
       end if;
    }
    

    你和我在一起吗?


    如果您尝试将一个家庭的所有成员放在一起,那么这取决于您使用的数据库系统是如何完成的,但请在您的文档中查找“层次查询”。

    【讨论】:

    • 啊,这是个好主意。所以我基本上使用一个连接而不是一个接一个地打开然后关闭它们。我会检查一下。多谢,伙计。 :)
    • 我认为是这样,但这在一定程度上取决于 StoredProc 正在做什么 - 如果其中有提交和回滚,它可能会开始变得非常混乱。
    • Uhm .. 实际上我不是 100% 确定我为什么要再插入一段时间,但我可能需要它.. 现在我看着它,虽然它看起来几乎没用。稍后我会看看它。存储过程顺便说一句只是一个简单的选择语句。
    • 好的,这似乎不起作用,因为数据读取器。我可以一遍又一遍地使用相同的连接,但这不包括数据读取器。我无法关闭它,因为 dr 仍在 while 循环中。所以……是的。另一方面,我将外部 while 更改为一个简单的 if 子句。这甚至可以解决我的问题,但我们会看到.. 如果有人找到另一种可能的解决方案,请告诉我。我会更新原帖。
    • @user854699 - 外部的while 有点像红鲱鱼,但它确实表明代码有点疯狂。有什么方法可以用简单的SELECT DISTINCT 查询替换存储过程调用来编译你想要的列表?如果没有关于您的数据结构和 SP 的更深入的信息,就很难在这方面走得更远。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-08-28
    • 2021-01-13
    • 1970-01-01
    • 2010-11-30
    • 1970-01-01
    • 1970-01-01
    • 2012-02-20
    相关资源
    最近更新 更多