Соединения пула соединений используются в TransactionScope - PullRequest
3 голосов
/ 16 марта 2012

Может кто-нибудь объяснить, почему мы испытываем общее потребление пула соединений при выполнении запросов внутри TransactionScope, в результате чего

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.

Я сократил нашу проблему до следующего:

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

После ответа Омера ниже, я думаю, что проблема объясняется лучше так:

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

Конечно, это не ожидаемое поведение? Я не читал ничего, что объясняет, почему это может происходить. Я могу только предположить, что это как-то связано с тем, как мы реализовали наши репозитории. Надеемся, что следующее даст достаточно хорошее описание реализации.

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)
    {
    }
}

Наша строка соединения довольно условна и оставляет количество соединений в пуле по умолчанию 100 (отсюда 101 итерация для проверки проблемы в моем коде выше).

1 Ответ

0 голосов
/ 18 апреля 2012

Вы создаете новые ссылки DataContext внутри цикла for.

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

Он сохраняет все эти данные в разных транзакциях.Если вы просто поместите код инициализации репо вне цикла for и выполните все операции в одном контексте, все будет хорошо.

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();
}
...