10

处理一个 SqlConnection 对象,但当然它并没有真正关闭。我需要关闭连接才能不锁定数据库对象。如何防止关闭的连接持有锁?


对上述句子的解释给不知道的人:

  • 当您关闭 ADO 或 ADO.NET 连接时,您实际上并没有切断与 SQL Server 的连接。ADO/ADO.NET 基础结构保持连接,以防您想再次使用它。连接一直在所谓的“连接池”中徘徊。

  • 几分钟不使用后,连接实际上会关闭。虽然,不是真的。TCP/IP 有它自己的方法来保持 TCP 连接打开几分钟(在“ CLOSE_WAIT ”状态)。这是在您要求再次打开到同一 IP:Port 的 TCP 连接时完成的。如果是这样,它可以使用已经打开的 TCP 连接。

  • 使用连接池和 SQL Server,仍会建立与 SQL Server 的连接。每个连接都有一个它所在的数据库上下文。只要一个连接位于该数据库中:它就持有该数据库上的共享数据库 (S-DB) 锁。

  • 共享数据库锁的意思很简单,“请不要在我在其中时删除此数据库。”

如何防止它在我的数据库上持有共享锁,同时保持连接池的好处?


我现在的临时解决方案是每次开发人员调用 Dispose:

connection.Dispose()

将其更改为对全局辅助函数的调用:

Database.DisposeConnection(connection);

它将数据库上下文更改为master

public static void DisposeConnection(SqlConnection connection)
{
    //Stop holding a database lock - in my database at least
    ADOHelper.ExecuteNonQuery(connection, "USE master");

    connection.Dispose();
}

它解决了我眼前的问题;关闭的连接没有锁定我的数据库。

但现在我担心连接池会扰乱它的大脑——因为我在它背后切换了数据库上下文。


如果有人不知道或不知道:

SDK

CloseDispose在功能上是等效的。

4

5 回答 5

7

您可以将数据库置于单用户模式以恢复它。IIRC,像这样的东西......

ALTER DATABASE TheDatabaseToRestore SET SINGLE_USER WITH  ROLLBACK IMMEDIATE;
RESTORE DATABASE TheDatabaseToRestore 
FROM DISK =N'Z:\Path\To\Backup\BackupFile';
ALTER DATABASE TheDatabaseToRestore SET MULTI_USER;

有关更多背景信息,请参阅:获取使用 SQL 恢复 SQL Server和/或恢复数据库备份的独占访问权限。

编辑: 单用户模式用于备份和恢复(在非快速版本中,我经常使用它)。使用它会踢出所有其他连接,并且无法建立新连接。我没有玩过各种“WITH”选项,例如“ROLLBACK IMMEDIATE”,但它们的用法似乎很简单。

于 2009-08-29T11:11:06.303 回答
3

你试过SqlClient.ClearPool吗?

来自 MSDN:

ClearPool 清除与连接关联的连接池。如果在调用时与 connection 关联的其他连接正在使用中,则它们会被适当地标记并在对其调用 Close 时被丢弃(而不是返回到池中)。

只需在每个连接上调用 ClearPool,但如果这样做,您将失去池化的好处。

public class DataFactory
{
  public SqlConnection CreateConnection(string connString)
  {
    SqlConnection conn = new SqlConnection(connString);
    SqlClient.ClearPool(conn);
    return conn;
   }
}

或者,您可以使用连接字符串的 Pooling 属性一起禁用池:

string connString = "Data Source=MYSERVER;Initial Catalog=myDb;Integrated Security=true;Pooling=false"
于 2009-08-28T17:30:25.633 回答
1

正如您所说,当您关闭或处置连接时,它会返回池中,但并未真正关闭。

然后你需要做什么来关闭池中的所有连接。这可以通过 ClearAllPools 命令完成。

ClearAllPools 重置(或清空)连接池。如果在调用时有正在使用的连接,它们会被适当地标记并在对其调用 Close 时被丢弃(而不是返回到池中)。

http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.clearallpools(VS.80).aspx

还有一个 ClearPool 命令可以执行相同的操作,但只针对单个连接。

希望这可以帮助

设拉子

于 2009-08-29T07:33:09.110 回答
1

执行“使用临时数据库;” 第一的。然后关闭它。

或者“USE master;”,如果这更符合您的喜好。

在正常生产操作期间,这些数据库中的任何一个上的 S-DB 锁定都无关紧要,因为您无法摆脱任何一个并继续运行服务器。

于 2009-08-31T18:23:05.397 回答
0

阅读评论,您想恢复它。

好的,让它离线。

恢复不是应用程序应该做的事情,所以 DBA 在 RESTORE 之前运行它。

ALTER DATABASE foo SET OFFLINE WITH ROLLBACK IMMEDIATE
于 2009-02-07T18:14:10.680 回答