5

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

在调试模式下,我查看了 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);
    }
}

“根据设计,大多数 Database 类方法在每次调用时处理与数据库的连接的打开和关闭。因此,应用程序代码不需要包含用于管理连接的代码。”。ExecuteReader 是一个例外(因为它返回一个资源)。ExecuteScalar 处于不确定状态:它返回一个“标量”。但是,我猜标量可能非常重,例如。从大型数据类型返回构造的 Stream,这需要保持连接打开。——莱姆斯·鲁萨努

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

我在 executeScalar() 中返回列 ID 并返回值 - 我知道这一点,因为仅在我收到一个值后才调用执行标量的下一个调用......它没有接缝有意义,流将永远保持开放我在 sql Management 中看到所有进程都在休眠。

4

1 回答 1

6
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将始终为全新的 Database 对象(如您的情况)创建一个新的连接,并将它们保存在内部字典中。Database 对象没有实现 Disposable,所以我无法确定到底应该由谁来清理这个TransactionScopeConnecitons内部列表中的连接。

马特,是否可以按照本文中有关 CLR 泄漏的步骤,查看您的进程中是否存在大量数据库对象?加载 SOS 并执行!dumpheap -type Microsoft.Practices.EnterpriseLibrary.Data.Database. 如果你发现很多物体,你能用!gcroot <AddressOfObject>

于 2009-07-23T06:29:02.267 回答