2011-12-21 16 views
2

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

我正在写一个Web应用程序(C#/ ASP.NET MVC 3,.NET框架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我跳过了一些不太相关的部分,比如完整性检查。我没有使用任何奥姆斯

,所有SP通过使用OdbcCommand情况下从代码中调用。每个函数调用都会创建新的OdbcConnection

我真诚地希望有人可以给我线索的问题。

UPD:如果我们只是快速创建一堆数据库,就会发生完全相同的问题。感谢大家的建议,在数据库中删除代码,但我宁愿有更普遍的问题的解决方案,或者至少暗示 - 甚至没有出现在所有的删除数据块的一个。

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()); 
    } 
} 

样品连接字符串:

​​
+0

'WITH ROLLBACK IMMEDIATE' SET SINGLE_USER使用该数据库将杀死其他连接。 – 2011-12-21 11:59:45

+0

@MartinSmith:这实际上是我们想要做的。我们有一些长期的请求,这将使得数据库无法快速删除。虽然我看到你的观点 - 这种说法可能会阻碍连接池的连接,对吧?这可能是导致此类行为的原因......无论如何,即使我们不删除数据库,也存在同样的问题。即使快速添加5个以上的数据库(当然有不同的名称)也会导致相同的结果。 – 2011-12-21 12:05:13

+0

我认为从调用程序接收到此错误消息?您是否检查过连接池是否被禁用? – ChrisBD 2011-12-21 12:17:01

回答

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; 
} 
+0

感谢您的回答!如果这能解决问题,那将是我曾经犯过的最愚蠢的错误。明天会检查你的建议。 – 2011-12-21 16:14:12

+0

非常感谢Chris,你的建议是正确的。经过一些修改,我使这个工作稳定。 P.S.完全订阅我之前的评论。这是我曾经犯过的该死的最愚蠢的错误。 – 2011-12-22 09:14:19

+0

很高兴能有所帮助。 – ChrisBD 2011-12-22 09:26:39