ADO.NET SQLServer: Как предотвратить удержание S-DB в закрытом соединении? - PullRequest
10 голосов
/ 06 февраля 2009

i Удалите объект SqlConnection, но, конечно, он на самом деле не закрыт . Мне нужно закрытое соединение, чтобы не удерживать блокировки на объектах базы данных. Как я могу предотвратить удержание замков закрытыми соединениями?


Объяснение вышеупомянутой отправки для тех, кто не знает:

  • Когда вы закрываете соединение ADO или ADO.NET, вы фактически не разрываете соединение с SQL Server. Инфраструктура ADO / ADO.NET поддерживает соединение на случай, если вы захотите использовать его снова. Соединения сохраняются в так называемом «пуле соединений».

  • После нескольких минут неиспользования соединение будет фактически закрыто. Хотя, не совсем. TCP / IP имеет свой собственный метод, позволяющий держать соединения TCP открытыми еще несколько минут (в состоянии « CLOSE_WAIT »). Это делается в случае, если вы снова попросите открыть TCP-соединение с тем же IP: Port. Если это так, он может использовать это уже открытое 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 :

Закрыть и Утилизировать функционально эквивалент.

Ответы [ 5 ]

7 голосов
/ 29 августа 2009

Вы можете поместить базу данных в однопользовательский режим для ее восстановления. 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 Server и / или Восстановление резервной копии базы данных с использованием SQL для получения дополнительной информации.

Редактировать: Однопользовательский режим предназначен для создания резервных копий и восстановления (для которых в неэкспресс-выпуске я регулярно его использую). Его использование удаляет все остальные соединения, и новые соединения не могут быть сделаны. Я не играл с различными опциями «WITH», такими как «ROLLBACK IMMEDIATE», но их использование кажется простым.

3 голосов
/ 28 августа 2009

Вы пробовали 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"
1 голос
/ 31 августа 2009

Выполнить «USE TempDB;» первый. Затем закройте его.

Или "USE master;", если вам так больше нравится.

Блокировки S-DB для любой из этих баз данных не должны иметь значения во время нормальной производственной работы, поскольку вы не можете избавиться ни от одной из них и все равно продолжить работу с сервером.

1 голос
/ 29 августа 2009

Как вы говорите, когда вы закрываете или удаляете соединение, оно возвращается в пул, но не закрывается.

Что нужно сделать, чтобы закрыть все соединения в пуле. Это можно сделать с помощью команды ClearAllPools.

ClearAllPools сбрасывает (или очищает) пул соединений. Если есть соединения, используемые во время звоните, они помечены соответствующим образом и будет отброшен (вместо возвращается в бассейн) при закрытии называется на них.

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

Существует также команда ClearPool, которая делает то же самое, но для одного соединения.

Надеюсь, это поможет

Шираз

0 голосов
/ 07 февраля 2009

Читая комментарий, вы хотите восстановить его.

ОК, отключите его.

Восстановление - это не то, что должно делать приложение, поэтому администратор базы данных запускает его до восстановления.

ALTER DATABASE foo SET OFFLINE WITH ROLLBACK IMMEDIATE
...