ADO.NET SQLServer:如何防止关闭连接持有S-DB锁?

时间:2009-02-06 15:30:04

标签: sql-server ado.net tcp connection-pooling

i Dispose一个SqlConnection对象,但当然是it isn't really closed。我需要关闭连接以不保持数据库对象的锁定。如何防止闭合连接锁定?


对于那些不知道的人说明上述信息:

  • 关闭ADO或ADO.NET连接时,实际上并未切断与SQL Server的连接。 ADO / ADO.NET基础结构可以保持连接,以防您再次使用它。这些连接在所谓的“连接池”中保持不变。

  • 几分钟未使用后,连接将实际关闭。虽然,不是真的。 TCP / IP有自己的方法来保持TCP连接打开几分钟(在“ CLOSE_WAIT ”状态)。如果您要求打开到同一IP:端口的TCP连接,则会执行此操作。如果是这样,它可以使用已经打开的TCP连接。

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

  • 共享数据库锁只是意味着“请不要删除此数据库。”

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


我的ad-hoc解决方案现在每次都是开发人员调用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();
}

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

但是现在我担心连接池会让它的大脑混乱 - 因为我在后面切换了数据库上下文。


如果有人不知道,或者不这么认为:

来自the SDK

  

关闭处理功能正常   等效。

5 个答案:

答案 0 :(得分: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;

请参阅:Obtain Exclusive Access to Restore SQL Server和/或Restore Database Backup using SQL了解更多背景信息。

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

答案 1 :(得分:3)

你试过SqlClient.ClearPool吗?

来自MSDN:

  

ClearPool清除连接池   与...有关   连接。如果有其他连接   与连接相关联正在使用中   在通话时,他们是   适当标记并被丢弃   (而不是返回到   pool)当他们调用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"

答案 2 :(得分:1)

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

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

  

ClearAllPools重置(或清空)连接池。如果有   在使用时使用的连接   打电话,他们被适当标记   并将被丢弃(而不是   关闭时返回池中   在他们身上被召唤。

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

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

希望这有帮助

西拉

答案 3 :(得分:1)

执行“USE TempDB;”第一。然后关闭它。

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

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

答案 4 :(得分:0)

阅读评论,您想恢复它。

好的,让它脱机。

还原不是应用程序应该做的事情,因此DBA在RESTORE之前运行它。

ALTER DATABASE foo SET OFFLINE WITH ROLLBACK IMMEDIATE