2017-01-02 88 views
0

我正在制作一个C#程序,它与一些SQL Server数据库进行交互。问题是如果我连接到数据库(dbA),然后关闭此连接并打开另一个数据库(dbB),然后执行dbA还原,则SqlException会触发说正在使用数据库(dbA)。但是,如果我执行程序并仅连接到dbB,则可以毫无问题地恢复其他数据库,就像保存第一个连接一样。反正这里是代码,其中的连接应打开和关闭:C# - SQL连接不会关闭

private bool CheckConnection() 
    { 
     bool res = false; 
     string conString = string.Empty; 
     if (!String.IsNullOrEmpty(serverBox.Text) && !String.IsNullOrEmpty(dbBox.Text)) 
     { 
      conString = ConcatConString(dbBox.Text); 
      using (SqlConnection conn = new SqlConnection(conString)) 
      { 
       conn.Open(); 
       if (conn.State == ConnectionState.Open) 
       { 
        res = true; 
       } 
      } 
     }   
     return res; 
    } 
+0

ADO.NET使用连接池,这意味着连接“重置”并保留在池中以供重用。您需要关闭应用程序或者只需强制所有客户端在恢复之前断开连接 –

+0

请使用堆栈跟踪添加完整的异常详细信息。另外,请分享调用此方法的代码。 –

+0

这不是一个主要问题,因为恢复意味着*所有*用户将失去他们试图保存的任何内容。最好的选择是将数据库置于单用户模式,如[此处显示](http://dba.stackexchange.com/questions/101917/unable-to-restore-database-backup-because-it-is-accessed- by-other-connection),它将回滚任何活动的事务,执行restor然后返回数据库到多用户模式 –

回答

3

ADO.NET使用连接池重用昂贵的连接对象。关闭连接时,任何现有事务都将回滚,其服务器端状态将重置,并将其置于连接池中,以供下一个Open命令使用。

尽管如此,当您尝试采取诸如关闭服务器,恢复数据库等激烈操作时仍然将其视为服务器连接。这意味着您必须采取明确的措施并告诉服务器它是好的继续。

在这种情况下,你需要将数据库设置为单用户模式,执行恢复操作,然后把它带回去多用户模式,如:

ALTER DATABASE [MyDB] SET SINGLE_USER WITH ROLLBACK IMMEDIATE 
RESTORE DATABASE [MyDB] ... 
ALTER DATABASE [MyDB] SET MULTI_USER 

这就是SSMS做对了的时候,您在恢复时检查“关闭现有数据库连接”选项

如果您想让现有连接花费一些时间来完成,也可以使用WITH ROLLBACK AFTER xx SECONDS。但是,在这种情况下,您将要覆盖数据库。

+0

我认为'ALTER DATABASE [MyDB] SET MULTI_USER'可能是不必要的,当您恢复数据库时,我认为它会自动将数据库设置回多用户模式。 –

+0

这是SSMS在检查“关闭连接”时生成的脚本。另外,如果'RESTORE'在数据库模式背后改变了数据库模式,那么在他有机会验证数据或继续进行差异备份之前,这将会令人不快。 [RESTORE](https://msdn.microsoft.com/en-us/library/ms186858.aspx)命令没有任何影响连接模式的选项 –

+0

谢谢!我一定会尝试,看起来是一个很好的解决方案 –

0

关闭连接的数据库不关闭它,它只是返回由ADO.Net保持连接池。通常我不会建议这样做,但看起来你可能有禁用连接池的合法情况。

在连接字符串中,将Pooling属性设置为nofalse,并且连接应该在服务器上实际关闭。

你可以看到它是如何工作的启动,或在下面的代码与禁用连接池的运行SSMS sp_who2

class Program 
{ 
    static void Main(string[] args) 
    { 
     SqlConnectionStringBuilder bldr = new SqlConnectionStringBuilder(); 
     bldr.IntegratedSecurity = true; 
     bldr.InitialCatalog = "YourDB"; 
     bldr.DataSource = "(localdb)\\YourServer"; 
     bldr.Pooling = false; //Comment and uncomment this and run sp_who2 

     using (SqlConnection con = new SqlConnection(bldr.ConnectionString)) 
     { 
      con.Open(); 
     } 
    } 
} 

更新

不这样做,除非你的程序是唯一连接的东西。我觉得这个程序专门用于恢复数据库。如果你在数据库上有其他客户端,那么这将会提高性能。

+2

没有理由禁用池。在还原期间使用SINGLE USER模式更容易。 –

+0

我想我误解了这个问题。 – Crowcoder