c# - C# DataBase.ExecuteScalar 中的连接泄漏

标签 c# sql database enterprise-library executescalar

静态类中的以下方法给了我一个超时异常,因为连接池已满。

在 Debug模式下,我查看了 sql Management studio,发现有 150 个休眠进程。

我希望连接自动关闭...我也尝试将其作为静态成员放置,但仍然出现相同的错误。

有什么想法吗? 这是代码:

public static Decimal ExecuteScalarDec(string procName, params object[] parameters)
{
    try
    {
        return (Decimal)DatabaseFactory.CreateDatabase().ExecuteScalar(procName, parameters);
    }
    catch (Exception ex)
    {
        throw new Exception(procName.ToString() + " " + parameters.ToString(), ex);
    }
}

"By design, most of the Database class methods handle the opening and closing of connections to the database on each call. Therefore, the application code does not need to include code for managing connections.". ExecuteReader is an exception (because it returns a resource). ExecuteScalar is in limbo: it returns a 'scalar'. However, I guess the scalar can be quite heavy, eg. a Stream constructed from a large datatype return, and that would require to keep the conenction open. – Remus Rusanu

我无法对您的回答发表评论,因为它说“评论需要 50 声望”在我注册用户后...

我在 executeScalar() 中返回一个列 Id 并返回值 - 我知道这一点是因为下一次调用执行标量只会在我收到一个值后调用... 流将永远保持开放是没有意义的 我在sql管理中看到所有进程都在休眠。

最佳答案

public static Decimal ExecuteScalarDec(string procName, params object[] parameters)
{
    try
    {
        using (Database database = DatabaseFactory.CreateDatabase())
        {
            return (Decimal)database.ExecuteScalar(procName, parameters);
        }
    }
    catch (Exception ex)
    {
        throw new Exception(procName.ToString() + " " + parameters.ToString(), ex);
    }
}

更新

好的,因为这是 EnterpriseLibrary 代码。 Database类像这样实现 ExecuetScalar(其他签名最终将崩溃为这个):

 public virtual object ExecuteScalar(DbCommand command)
        {
            if (command == null) throw new ArgumentNullException("command");

            using (ConnectionWrapper wrapper = GetOpenConnection())
            {
                PrepareCommand(command, wrapper.Connection);
                return DoExecuteScalar(command);
            }
        }

并且 ConnectionWrapper 处理连接(链接中源文件的末尾),因此,从理论上讲,您的调用应该正常并处理连接。

GetOpenConnection() 方法返回一个确实处理连接的包装器...除非当前存在一个连接 TransactionScopeConnections :

 protected ConnectionWrapper GetOpenConnection(bool disposeInnerConnection)
    {
        DbConnection connection = TransactionScopeConnections.GetConnection(this);
        if (connection != null)
        {
            return new ConnectionWrapper(connection, false);
        }

        return new ConnectionWrapper(GetNewOpenConnection(), disposeInnerConnection);
    }

这里是如何TransactionScopeConnections返回连接:

  public static DbConnection GetConnection(Database db)
    {
        Transaction currentTransaction = Transaction.Current;

        if (currentTransaction == null)
            return null;

        Dictionary<string, DbConnection> connectionList;
        DbConnection connection;

        lock (transactionConnections)
        {
            if (!transactionConnections.TryGetValue(currentTransaction, out connectionList))
            {
                // We don't have a list for this transaction, so create a new one
                connectionList = new Dictionary<string, DbConnection>();
                transactionConnections.Add(currentTransaction, connectionList);

                // We need to know when this previously unknown transaction is completed too
                currentTransaction.TransactionCompleted += OnTransactionCompleted;
            }
        }

        lock (connectionList)
        {
            // Next we'll see if there is already a connection. If not, we'll create a new connection and add it
            // to the transaction's list of connections.
            // This collection should only be modified by the thread where the transaction scope was created
            // while the transaction scope is active.
            // However there's no documentation to confirm this, so we err on the safe side and lock.
            if (!connectionList.TryGetValue(db.ConnectionString, out connection))
            {
                // we're betting the cost of acquiring a new finer-grained lock is less than 
                // that of opening a new connection, and besides this allows threads to work in parallel
                connection = db.GetNewOpenConnection();
                connectionList.Add(db.ConnectionString, connection);
            }
        }

        return connection;
    }

现在,除非我弄错了,TransactionsScopeConnections将始终为全新的数据库对象创建一个新的连接(如您的情况)并将它们保存在内部字典中。数据库对象没有实现 Disposable,因此我无法确定究竟应该由谁来清理来自此 TransactionScopeConnecitons 的连接。内部列表。

马特,是否可以按照 this article about CLR leaks 中的步骤操作看看你的进程中是否有大量的数据库对象?加载 SOS 并执行 !dumpheap -type Microsoft.Practices.EnterpriseLibrary.Data.Database .如果你找到很多对象,你能用 !gcroot <AddressOfObject> 跟踪其中一些对象上的引脚堆栈吗?

关于c# - C# DataBase.ExecuteScalar 中的连接泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1169940/

相关文章:

java - Hibernate 与引用列的一对一映射(XML 映射)

c# - 使用秒表测量抽象方法运行时间

sql - 用于获取用户关联数据的 Rails 或 SQL 查询

sql - 如何从数据库中获取带有父记录的最后一个子记录

mysql - 如何将列值作为mysql中where条件中的变量

sql - 工作表范围内定义的名称的表名称是什么?

mysql - (数据库设计,mysql)我的数据库设计适合基本的购物车吗?(我是数据库设计的新手)

c# - Crystal Reports - 如果包含图表,则数据重复

C#套接字数据报溢出

c# - 如何在运行时将程序重置为默认配置?