在TransactionScope中消耗的连接池连接

时间:2012-03-15 20:55:50

标签: sql-server-2008 linq-to-sql connection-pooling transactionscope

有人可以解释为什么我们在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();
    }
}

修改

在Omer的回答之后,我认为这个问题的解释更好:

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 :(得分:0)

您正在for循环中创建新的DataContext引用。

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

它将所有这些保留在不同的交易中。如果你只是将repo init代码放在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();
}