3 Stimmen

Verbindungen des Verbindungspools, die in TransactionScope verbraucht werden

Kann jemand erklären, warum beim Ausführen von Abfragen innerhalb von TransactionScope eine vollständige Auslastung des Verbindungspools auftritt, was zu

System.InvalidOperationException: Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.

Ich habe unser Problem auf Folgendes reduziert:

SomeNonTransactionalCode()
{
    // This code will execute with just one connection to the database
    // and complete without exception

   List<BusinessEntity> beList;

   for (int i = 0; i < 101; i++)
   {
       BusinessEntityRepository beRepo = new BusinessEntityRepository();
       beList = beRepo.ReadAll().ToList();
   }
}

SomeTransactionalCode()
{
    // This code will cause the connections to the database to increment
    // with every iteration eventually timing out after 100 connections

    using (TransactionScope transactionScope = new TransactionScope())
    {
        List<BusinessEntity> beList;

        for (int i = 0; i < 101; i++)
        {
            BusinessEntityRepository beRepo = new BusinessEntityRepository();
            beList = beRepo.ReadAll().ToList();
        }

        transactionScope.Complete();
    }
}

EDIT

Nach der Antwort von Omer unten denke ich, dass das Problem so besser erklärt werden kann:

SomeNonTransactionalCode()
{
    // This code will execute with just one connection to the database

   List<BusinessEntity1> be1List;
   BusinessEntity1Repository be1Repo = new BusinessEntity1Repository();
   be1List = be1Repo .ReadAll().ToList();

   List<BusinessEntity2> be2List;
   BusinessEntity2Repository be2Repo = new BusinessEntity2Repository();
   be2List = be2Repo .ReadAll().ToList();

   List<BusinessEntity3> be3List;
   BusinessEntity3Repository be3Repo = new BusinessEntity3Repository();
   be3List = be3Repo.ReadAll().ToList();

}

SomeTransactionalCode()
{
    // This code will cause three seperate connections to the database

    using (TransactionScope transactionScope = new TransactionScope())
    {
        // note this is simplified - the code below could be in unknown nested
        // methods make creating of the repos prior to calling not possible

        List<BusinessEntity1> be1List;
        BusinessEntity1Repository beRepo1 = new BusinessEntity1Repository();
        be1List = be1Repo.ReadAll().ToList();

        List<BusinessEntity2> be2List;
        BusinessEntity2Repository beRepo2 = new BusinessEntity2Repository();
        be2List = be2Repo.ReadAll().ToList();

        List<BusinessEntity3> be3List;
        BusinessEntity3Repository beRepo3 = new BusinessEntity3Repository();
        be3List = be3Repo.ReadAll().ToList();

        transactionScope.Complete();
    }
}

Das ist doch sicher kein erwartetes Verhalten? Ich habe nichts gelesen, was erklärt, warum dies der Fall sein könnte. Ich kann nur vermuten, dass es etwas damit zu tun hat, wie wir unsere Repositories implementiert haben. Ich hoffe, dass das Folgende eine ausreichende Beschreibung der Implementierung liefert.

public class BusinessEntityRepository
{
    private BusinessEntityDal Dal { get; set; }

    public BusinessEntityRepository()
    {
        this.Dal = new BusinessEntityDal ();
    }

    public IQueryable<BusinessEntity> ReadAll()
    {
        IQueryable<BusinessEntity> query = null;
        if (Dal != null)
        {
            query = Dal.ReadAll();
        }

        //-Return
        return query;
    }
}

public class BusinessEntityDal : BaseDal 
{
    public IQueryable<BusinessEntity> ReadAll()
    {
        var result = from de in this.DC.BusinessEntityTable
                         select new BusinessEntity
                         {
                             Property1 = Column1,
                             Property2 = Column2,
                             // etc... 
                         };
        //-Return
        return (result);
    }
}

public abstract class BaseDal
{
    protected OurDataContext DC;

    public BaseDal()
    {
        // create a DataContext
        this.DC = new OurDataContext();
    }
}

public class OurDataContext : System.Data.Linq.DataContext
{       
    private static readonly string _cn = // some static connection string taken from web.config
    public OurDataContext()
        : base(OurDataContext._cn)
    {
    }
}

Unsere Verbindungszeichenfolge ist recht konventionell und belässt die Anzahl der Verbindungen im Pool auf der Standardeinstellung 100 (daher die 101 Iterationen, um das Problem in meinem obigen Code zu testen).

0voto

Omer Cansizoglu Punkte 1241

Sie erstellen neue DataContext-Referenzen innerhalb der for-Schleife.

for (int i = 0; i < 101; i++)
    {
        BusinessEntityRepository beRepo = new BusinessEntityRepository();
        beList = beRepo.ReadAll().ToList();
    }

All das wird in verschiedenen Transaktionen festgehalten. Wenn Sie den Repo-Initialisierungscode außerhalb der for-Schleife platzieren und alle Operationen in einem Kontext durchführen, ist das in Ordnung.

using (TransactionScope transactionScope = new TransactionScope())
{
    List<BusinessEntity> beList;
    BusinessEntityRepository beRepo = new BusinessEntityRepository();
    for (int i = 0; i < 101; i++)
    {

        beList = beRepo.ReadAll().ToList();
    }
    //do some other things with same context

    transactionScope.Complete();
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X