2009-07-17 13 views
34

Entiendo que si instalo un objeto SqlConnection, realmente estoy agarrando una conexión de un grupo de conexiones. Cuando llamo a Open(), se abrirá la conexión. Si llamo al método Close() o Dispose() en ese objeto SqlConnection, se devuelve al grupo de conexiones.¿Cómo forzar a una SqlConnection a cerrar físicamente, mientras usa la agrupación de conexiones?

Sin embargo, eso realmente no me dice si realmente está cerrado, o si todavía tengo una conexión activa a la base de datos.

¿Cómo puedo forzar que una conexión SqlConnection se cierre a nivel de red, o al menos indicar cuándo se cierra?

Ejemplo:

using(SqlConnection conn = new SqlConnection(DBConnString)) { 

    conn.Open(); 
    SqlCommand cmd = conn.CreateCommand(); 
    ... 
    cmd.ExecuteReader(CommandBehavior.CloseConnection); 
    ... 
} 
  • Primera corrida: 300 ms
  • segunda pasada: 100 ms
  • tercera carrera: 100 ms
  • después de esperar un largo tiempo (30 minutos) : 300 ms

If la conexión estaba VERDADERAMENTE cerrada, la segunda y tercera ejecución también debería ser de 300 ms. Pero sé que la conexión no está verdaderamente cerrada para esas ejecuciones (revisé el monitor de actividad del servidor SQL). No se requieren 200 ms adicionales para realizar la autenticación/etc.

¿Cómo fuerzo la conexión a cerrar realmente?

Ideas

  • ¿El CommandBehavior.CloseConnection trabajar? (¿Aparentemente no?)
  • ¿Funciona el ajuste "Max Pool Size = 0" en la cadena de conexión? (Esta sería una solución pírrica)
  • ¿Dispose() funciona?

Referencias

Respuesta

48
+2

+1 para que el primer respondedor lea correctamente la pregunta. – Joe

+1

Estoy haciendo esto, pero mi conexión de SQL todavía aparece en sp_who2 y mis AppLocks en sesión de SQL permanecen bloqueados (tengo la intención de que mueran con la conexión). Incluso configuro ['connStrBuilder.Polling = false'] (https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.close (v = vs.110) .aspx). –

0

CommandBehavior.CloseConnection suele desanimarse a causa de este hecho - No se puede estar seguro de que la conexión se cerrará. (Trataré de encontrar alguna evidencia concreta de esto, lo digo por un recuerdo débil).

Dispose() es el manera más segura porque llama implícitamente Close().

La construcción using demostrada por @Alex es simplemente otra forma (amigable con el programador) de escribir la construcción try-finally con la eliminación implícita de objetos añadida.

Editar: (después de la edición de cuestionar)

su preocupación por las conexiones realidad de cierre parece injustificada a mí. La conexión simplemente volverá al grupo para que pueda reutilizarse fácilmente sin tener que pasar por toda la inicialización. Esto no significa que la conexión todavía está conectada activamente a la base de datos.

+2

Una conexión en la agrupación ** does ** significa que todavía está conectado de forma activa a la base de datos. Por ejemplo, puede cerrar un objeto de Conexión y aún tendrá un bloqueo de base de datos shard debido a que la conexión aún está en el grupo (http: // stackoverflow.com/questions/520716/ado-net-sqlserver-how-to-prevent-closed-connection-from-holding-s-db-lock) –

9

Si no desea utilizar el grupo de conexiones, debe especificarlo en su propiedad SqlConnection.ConnectionString. Por ejemplo

"Data Source=MSSQL1;Database=AdventureWorks;Integrated Security=true;Pooling=false;" 

Eliminación o cerrar el objeto SqlConnection es sólo va a cerrar la conexión y devolverlo a la agrupación de conexiones.

3

Generalmente, desea que el grupo de conexiones haga su trabajo; no desea que la conexión se cierre realmente.

¿Por qué específicamente desea que la conexión no regrese a la piscina?

+2

Una conexión en el grupo de piscinas mantendrá bloqueos. –

+1

No estoy seguro de a qué tipo de bloqueos se refiere: una conexión eliminada cuya conexión subyacente se devuelve al conjunto de conexiones no debe participar en ninguna transacción ni contener bloqueos relevantes para el código de consumo. Por supuesto, sigue usando un puerto de red y algunos otros recursos, pero el costo de adquisición de estos recursos es * por qué * usted * no * qué liberarlos. A menos que intente eliminar/restaurar la base de datos subyacente o algo similarmente radical, estos bloqueos no son problemáticos. –

+1

Una conexión en el grupo puede evitar el acceso exclusivo a una base de datos. – kevmar

23

La respuesta de Moe Sisko (llamada SqlConnection.ClearPool) es correcta.

A veces se necesita una conexión para realmente cerrar en lugar de volver a la piscina. Como ejemplo, tengo una prueba de unidad que crea una base de datos temporal, construye el esquema, prueba algunas cosas, luego descarta la base de datos temporal si todas las pruebas pasan.

Cuando la agrupación de conexiones está activa, falla el comando de la base de datos porque todavía hay conexiones activas. Desde el punto de vista del programador, todas las SQLConnections están cerradas, pero como la agrupación aún mantiene una abierta, SQL Server no permitirá la caída.

La mejor documentación sobre cómo se maneja la agrupación de conexiones es this page on SQL Server Connection Pooling en MSDN. Uno no quiere desactivar por completo la agrupación de conexiones porque mejora el rendimiento con aperturas y cierres repetidos, pero a veces es necesario llamar a un "cierre forzado" en una SQLConnection para que se suelte de la base de datos.

Esto se hace con ClearPool. Si llama al SqlConnection.ClearPool(connection) antes de cerrar/desechar, cuando lo cierre/elimine realmente desaparecerá.

+0

El caso de uso que describe es casi exactamente lo que estaba haciendo: probar el rendimiento de ciertos patrones de acceso a db, utilizar cachés de datos/procedimientos "en frío" y, por supuesto, las conexiones. –

+0

El enlace que proporcionó se agregó al texto de la pregunta. Gracias. –

+0

Mismo escenario para mí :-) –

-2

La respuesta de Robert de SqlConnection.ClearPool(TheSqlConn) hizo exactamente lo que yo quería. Es bueno saber que se puede interactuar con el grupo cuando sea necesario.

Mi caso de uso fue: Hemos arruinado una conexión y la hemos dejado volver al grupo, cómo detectar que está arruinada y actualizarla, para que el próximo usuario no tenga problemas.

La solución fue: detectar que acabamos de arruinar la conexión y eliminarla completamente de la agrupación, permitiendo que la agrupación se vuelva a llenar con nuevas conexiones.

Una década escribiendo SqlClient.SqlConnection y nunca pensé en interactuar con el grupo hasta hoy.

Cuestiones relacionadas