sql-server - net - sqlconnection c# ejemplo
ADO.NET SQLServer: ¿Cómo evitar que la conexión cerrada mantenga presionado S-DB lock? (5)
Descarte un objeto SqlConnection, pero por supuesto no está realmente cerrado . Necesito una conexión cerrada para no mantener bloqueos en los objetos de la base de datos. ¿Cómo puedo evitar que las conexiones cerradas tengan bloqueos?
Explicación del párrafo anterior para aquellos que no saben:
Cuando cierra una conexión ADO o ADO.NET, en realidad no está cortando la conexión a SQL Server. La infraestructura ADO / ADO.NET mantiene la conexión en caso de que quiera volver a utilizarla. Las conexiones se mantienen en todo lo que se llama "The Connection Pool".
Después de unos minutos de no usarse, la conexión se cerrará realmente . Aunque, en realidad no. TCP / IP tiene su propio método para mantener abiertas las conexiones TCP durante unos minutos más (en el estado " CLOSE_WAIT "). Esto se hace en caso de que solicite abrir nuevamente una conexión TCP a la misma IP: Puerto. Si es así, puede usar esa conexión TCP ya abierta.
Con la agrupación de conexiones y SQL Server, la conexión aún se establece en SQL Server. Cada conexión tiene un contexto de base de datos en el que se encuentra. Siempre que una conexión esté asentada en esa base de datos: tiene un bloqueo de base de datos compartida (S-DB) en esa base de datos.
Un bloqueo de base de datos compartida simplemente significa, "No elimine esta base de datos mientras estoy en ella, por favor".
¿Cómo puedo evitar que mantenga un bloqueo compartido en mi base de datos, manteniendo los beneficios de la agrupación de conexiones?
Mi solución ad-hoc ahora es cada vez que un desarrollador llamado Dispose:
connection.Dispose()
cámbielo a una llamada a una función de ayuda global:
Database.DisposeConnection(connection);
que cambia el contexto de la base de datos a maestro :
public static void DisposeConnection(SqlConnection connection)
{
//Stop holding a database lock - in my database at least
ADOHelper.ExecuteNonQuery(connection, "USE master");
connection.Dispose();
}
Soluciona mi problema inmediato; las conexiones cerradas no tienen un bloqueo en mi base de datos.
Pero ahora me preocupa que la combinación de conexiones tenga su cerebro revuelto, porque cambié los contextos de las bases de datos a sus espaldas.
En caso de que alguien no supiera, o pensara lo contrario:
Del SDK :
Close y Dispose son funcionalmente equivalentes.
Leyendo el comentario, quieres restaurarlo.
OK, tómalo fuera de línea.
La restauración no es algo que una aplicación debería hacer, por lo que el DBA ejecuta esto antes de RESTORE.
ALTER DATABASE foo SET OFFLINE WITH ROLLBACK IMMEDIATE
¿Has probado SqlClient.ClearPool ?
Desde MSDN:
ClearPool borra el grupo de conexiones que está asociado con la conexión. Si hay conexiones adicionales asociadas con la conexión en el momento de la llamada, se marcan adecuadamente y se descartan (en lugar de devolverse al grupo) cuando se invoca Close.
Simplemente llame a ClearPool en cada conexión, pero perderá los beneficios de agrupación si lo hace.
public class DataFactory
{
public SqlConnection CreateConnection(string connString)
{
SqlConnection conn = new SqlConnection(connString);
SqlClient.ClearPool(conn);
return conn;
}
}
Alternativamente, puede deshabilitar la agrupación en conjunto usando la propiedad Pooling de la cadena de conexión:
string connString = "Data Source=MYSERVER;Initial Catalog=myDb;Integrated Security=true;Pooling=false"
Como dices cuando cierras o descartas una conexión, regresa al grupo pero no está realmente cerrada.
Lo que debe hacer para cerrar todas las conexiones en el grupo. Esto se puede hacer con un comando ClearAllPools.
ClearAllPools restablece (o vacía) el grupo de conexiones. Si hay conexiones en uso en el momento de la llamada, se marcan adecuadamente y se descartarán (en lugar de devolverse al grupo) cuando se invoca Close.
También hay un comando ClearPool que hace lo mismo, pero para una sola conexión.
Espero que esto ayude
Shiraz
Ejecute "USE TempDB"; primero. Luego ciérralo.
O "USE master;", si eso es más de su agrado.
Los bloqueos de S-DB en cualquiera de esas bases de datos no deberían importar durante la operación de producción normal, ya que no puede deshacerse de ninguno de ellos y continuar ejecutando el servidor de todos modos.
Puede colocar la base de datos en modo de usuario único para restaurarla. IIRC, algo como esto ...
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;
ver: Obtenga Acceso Exclusivo para Restaurar Servidor SQL y / o Restaurar Copia de Seguridad de la Base de Datos usando SQL para más antecedentes.
Editar: El modo de usuario único está destinado a copias de seguridad y restauraciones (que, en la edición no explícita, es para lo que lo uso regularmente). Al usarlo se eliminan todas las demás conexiones y no se pueden hacer nuevas conexiones. No he jugado con las diversas opciones "CON", como con "ROLLBACK INMEDIATO", pero su uso parece sencillo.