快速创建/删除数据库时,“已禁用连接”错误消息

时间:2011-12-21 11:54:39

标签: c# sql-server odbc stress-testing

简介

我正在编写一个Web应用程序(C#/ ASP.NET MVC 3,.NET Framework 4,MS SQL Server 2008,System.Data.ODBC用于数据库连接),我在数据库创建方面遇到了一些问题/删除。

我要求应用程序应该能够创建和删除数据库。

问题

应用程序无法对该功能进行压力测试。更具体地说,如果客户端开始快速创建,删除,再次创建具有相同名称的数据库,则最终(〜第5次请求)服务器代码抛出ODBCException“连接已被禁用。”。在已执行测试的所有计算机上都会观察到此行为 - 确切的失败请求可能不是第5个,而是在该值附近。

研究

谷歌搜索异常给出了非常低的输出 - 异常似乎非常通用,没有发现模拟问题。我发现的一个建议是我的开发Windows 7可能无法处理多个同时连接,因为它不是服务器操作系统。我尝试在Windows 2008 Server上安装我们的应用程序 - 行为几乎没有变化,只是在异常发生之前处理了更多的请求。

有关实施的代码和其他评论

使用以下存储过程创建数据库:

CREATE PROCEDURE [dbo].[sp_DBCreate]
...     
    @databasename nvarchar(124)     -- 124 is max length of database file names
AS
    DECLARE @sql nvarchar(150);
BEGIN
...
    -- Create a new database
    SET @sql = N'CREATE DATABASE ' + quotename(@databasename, '[');
    EXEC(@sql);

    IF @@ERROR <> 0
        RETURN -2;
...    
    RETURN 0;
END

使用以下SP删除数据库:

CREATE PROCEDURE [dbo].[sp_DomainDelete]
...
    @databasename nvarchar(124)     -- 124 is max length of database file names
AS
    DECLARE @sql nvarchar(200);
BEGIN
...
    -- check if database exists
    IF EXISTS(SELECT * FROM [sys].[databases] WHERE [name] = @databasename)
    BEGIN
        -- drop all active connections
        SET @sql = N'ALTER DATABASE' + quotename(@databasename, '[') + ' SET SINGLE_USER WITH ROLLBACK IMMEDIATE';
        EXEC(@sql);
            -- Delete database
        SET @sql = N'DROP DATABASE ' + quotename(@databasename, '[');
        EXEC(@sql);

        IF @@ERROR <> 0
            RETURN -1;  --error deleting database
    END
    --ELSE database does not exist. consider it deleted.

    RETURN 0; 
END

在两个SP中,我都跳过了较少相关的部分,例如健全性检查。

我没有使用任何ORM,所有SP都是通过使用OdbcCommand实例从代码中调用的。为每个函数调用创建新的OdbcConnection

我真诚地希望有人能给我这个问题的线索。

UPD :如果我们只是快速创建一堆数据库,就会出现完全相同的问题。感谢大家对数据库删除代码的建议,但我更愿意有一个解决方案或者至少提供一个更普遍的问题的提示 - 即使不删除DB也会出现这个问题。

UPD2 :以下代码用于SP调用:

public static int ExecuteNonQuery(string sql, params object[] parameters)
{
    try
    {
        var command = new OdbcCommand();
        Prepare(command, new OdbcConnection( GetConnectionString() /*irrelevant*/), null, CommandType.Text, sql,
          parameters == null ?
          new List<OdbcParameter>().ToArray() :
          parameters.Select(p => p is OdbcParameter ? (OdbcParameter)p : new OdbcParameter(string.Empty, p)).ToArray());

        return command.ExecuteNonQuery();
    }
    catch (OdbcException ex)
    {
        // Logging here
        throw;
    }
}

public static void Prepare(
    OdbcCommand command, 
    OdbcConnection connection, 
    OdbcTransaction transaction, 
    CommandType commandType, 
    string commandText, 
    params OdbcParameter[] commandParameters)
{
    if (connection.State != ConnectionState.Open)
    {
        connection.Open();
    }
    command.Connection = connection;
    command.CommandText = commandText;
    if (transaction != null)
    {
        command.Transaction = transaction;
    }
    command.CommandType = commandType;
    if (commandParameters != null)
    {
        command.Parameters.AddRange(
            commandParameters.Select(p => p.Value==null && 
                p.Direction == ParameterDirection.Input ?
                    new OdbcParameter(p.ParameterName, DBNull.Value) : p).ToArray());
    }
}

示例连接字符串:

Driver={SQL Server}; Server=LOCALHOST;Uid=sa;Pwd=<password here>;

1 个答案:

答案 0 :(得分:1)

好。 OdbcConnection可能存在范围问题,但在完成连接后,您似乎也没有关闭连接。这可能意味着您依赖池管理器来关闭未使用的连接,并在它们超时时将它们返回池中。完成后,using块将自动关闭并处理连接,允许它返回到连接池。

试试这段代码:

public static int ExecuteNonQuery(string sql, params object[] parameters)
{
    int result = 0;
        try
        {
            var command = new OdbcCommand();
            using (OdbcConnection connection = new OdbcConnection(GetConnectionString() /*irrelevant*/))
            {
               connection.Open();
               Prepare(command, connection, null, CommandType.Text, sql,
                       parameters == null ?
                                           new List<OdbcParameter>().ToArray() :
                                           parameters.Select(p => p is OdbcParameter ? (OdbcParameter)p : new OdbcParameter(string.Empty, p)).ToArray());

               result = command.ExecuteNonQuery();
            }

        }
        catch (OdbcException ex)
        {
            // Logging here
            throw;
        }
    return result;
}