2013-04-09 2 views
1

В настоящее время у меня есть серьезная проблема с одним из моих веб-приложений, которое запускается в Timeout Exception около полудюжины раз в день.InvalidOperationException: Timeout - рекурсивный доступ к БД

Ошибка: «Период ожидания, прошедший до получения соединения из пула. Возможно, это произошло из-за того, что были использованы все объединенные соединения и максимальный размер пула».

После многих поисковых запросов я выяснил, что проблема имеет какое-то отношение к незамкнутым соединениям. Поэтому я проверил все функции, которые имеют доступ к базе данных в любом случае, пока я не наткнулся на это один:

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 

Как вы можете видеть эту функцию выполняет хранимую процедуру и запускает результаты через время цикла, где он вызывает функцию снова если определенное условие - значениеInColl-. Таким образом, возможно, что существует 20 или более открытых соединений. Он не имеет ничего общего с значением тайм-аута, которое устанавливается через GetDataReaderFromStoredProcedure до 600, которое на самом деле должно быть достаточно. Разумеется, я удвоил стоимость и выкажу ее сегодня вечером. Я посмотрю, помогло ли это в следующий день. Я считаю, что проблема в том, что слишком много открытых подключений одновременно, из-за рекурсивной функции, но я не знаю, как это решить.

Я не мог найти ничего о том, как отредактировать максимальные соединения. Я даже не совсем уверен, где его установить. Это IIS, сама БД или это параметр программирования (VB.net/ASP.NET). Было бы хорошо, если бы вы, ребята, могли помочь мне здесь.

[EDIT] Хорошо, у кого-то возникла идея повторно использовать переменную соединения, но это не сработает, поскольку datareader все еще работает. Пока он не закрыт, я не могу повторно использовать соединение, и я не могу закрыть datareader, потому что я могу потерять данные, если я это сделаю. В то время как петля для dr.read не закончился, но .. С другой стороны, я удалил (в значительной степени бесполезна) внешний, а и б Условный пункт в обмен:

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 

ответ

1

Есть ли почему вы не можете реорганизовать вещи так, чтобы каждая рекурсия использовала одно и то же соединение db?

Я не VB кодировщик, но я бы решить ее следующим образом

  1. Изменение getOrgas() принять параметры соединения по умолчанию это «ничего».
  2. Изменение Dim conn линии if IsNothing(connParameter) conn = GetConnection() else conn := connParameter;
  3. Измените вашу рекурсии строку getOrgas(orgatmp, conn);
  4. Протестируйте F %%%% из него.

Я только что заметил внешнюю петлю While. Это просто вас смущает? Сколько раз он будет выполняться? ...


Я действительно задавался вопросом о DataReader - попробовать это - я вижу, что ваш DataReader нужно закрыть, прежде чем рекурсию, так что закрыть его.

в псевдокоде -

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; 
} 

Вы со мной?


Если вы пытаетесь собрать все член семьи, то это зависит, какую систему базы данных вы используете, как это делается, но искать «Heirarchical запросов» в документации.

+0

Ах, это отличная идея. Поэтому я в основном использую одно соединение вместо того, чтобы открываться один за другим и закрывать его потом. Я проверю это. Спасибо приятель. :) – OhSnap

+0

Я так думаю, но это немного зависит от того, что делает StoredProc - если есть коммиты и откаты, там все может начаться очень беспорядочно. –

+0

Uhm .. На самом деле я не уверен на 100%, почему я вставил другое, но мне это, вероятно, нужно ... Теперь, когда я смотрю на него, хотя кажется, что это бесполезно. Я посмотрю на это позже. Хранимая процедура - это просто простой оператор select. – OhSnap