数据库
首页 > 数据库> > C#多线程应用程序和SQL连接帮助

C#多线程应用程序和SQL连接帮助

作者:互联网

关于我编写的应用程序,我需要一些建议.我遇到的问题是由于DAL和与SQL Server 2008数据库的连接未关闭而引起的,但是我查看了我的代码,每个连接始终处于关闭状态.

该应用程序是一个多线程应用程序,它检索一组记录,并且在处理记录时会更新有关该记录的信息.

流程如下:

管理员可以设置要运行的线程数以及每个线程要拉取多少条记录.

这是他们单击开始后运行的代码:

适配器是我DAL的抽象,这里是它们的外观示例:

public class UserDetailsAdapter: IDataAdapter<UserDetails>
{
     private IUserDetailFactory _factory;

        public UserDetailsAdapter()
        {
            _factory = new CampaignFactory();
        }

        public UserDetails FindById(int id){
             return _factory.FindById(id);
        }
}

调用_factory后,它将立即处理SQL,并立即关闭连接.

线程应用的代码:

private int _recordsPerthread;


private int _threadCount;

    public void RunDetails()
    {
        //create an adapter instance that is an abstration
        //of the data factory layer
        var adapter = new UserDetailsAdapter();

        for (var i = 1; i <= _threadCount; i++)
        {
            //This adater makes a call tot he databse to pull X amount of records and 
            //set a lock filed so the next set of records that are pulled are differnt.
            var details = adapter.FindTopDetailsInQueue(_recordsPerthread);
            if (details != null)
            {
                var parameters = new ArrayList {i, details};
                ThreadPool.QueueUserWorkItem(ThreadWorker, parameters);
            }
            else
            {
                break;
            }
        }
    }

    private void ThreadWorker(object parametersList)
    {
        var parms = (ArrayList) parametersList;
        var threadCount = (int) parms[0];
        var details = (List<UserDetails>) parms[1];
        var adapter = new DetailsAdapter();


        //we keep running until there are no records left inthe Database
        while (!_noRecordsInPool)
        {
            foreach (var detail in details)
            {
                var userAdapter = new UserAdapter();
                var domainAdapter = new DomainAdapter();

                var user = userAdapter.FindById(detail.UserId);
                var domain = domainAdapter.FindById(detail.DomainId);

                //...do some work here......

                adapter.Update(detail);
            }

            if (!_noRecordsInPool)
            {
                details = adapter.FindTopDetailsInQueue(_recordsPerthread);


                if (details == null || details.Count <= 0)
                {
                    _noRecordsInPool = true;
                    break;
                }
            }
        }
    }

该应用程序崩溃是因为似乎存在与数据库的连接问题.在我的日志文件中查找DAL,我看到以下信息:

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

当我在一个线程中运行它时,它工作正常.我猜想当我在多个线程中破坏他的时候,很明显我与数据库建立了太多的连接.关于如何使它在多个线程中运行以及如何确保数据库不会出现任何错误的任何想法.

更新:
我认为我的问题可能是数据库中的僵局.这是我遇到死锁错误时正在运行的SQL中的代码:

WITH cte AS ( 
  SELECT TOP (@topCount) *
  FROM
  dbo.UserDetails WITH (READPAST) 
WHERE
  dbo.UserDetails where IsLocked = 0)

UPDATE cte 
  SET 
  IsLocked = 1

  OUTPUT INSERTED.*;

之前(在其他应用程序中),我从未遇到过与此代码相关的问题.我对索引进行了重组,因为它们的碎片占99%.那没有帮助.我在这里茫然.

解决方法:

我对代码连接在何处打开感到困惑,但是您可能希望数据适配器实现IDispose(确保在使用范围离开时确保关闭池连接)并将代码包装在using块中:

using (adapter = new UserDetailsAdapter())
{
    for (var i = 1; i <= _threadCount; i++)
    {
        [..]
    }
} // adapter leaves scope here; connection is implicitly marked as no longer necessary

ADO.NET使用连接池,因此不需要(可能会适得其反)显式打开和关闭连接.

标签:multithreading,net-3-5,sql,c
来源: https://codeday.me/bug/20191209/2095953.html