net - pool de conexiones c#
¿Cómo forzar a una SqlConnection a cerrar físicamente, al usar la agrupación de conexiones? (6)
Entiendo que si instancia 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.
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 en el nivel de la 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 ejecución: 300 ms
- Segunda ejecución: 100 ms
- Tercera ejecución: 100 ms
- Después de esperar mucho tiempo (30 minutos): 300 ms
Si la conexión realmente se cerraba, la segunda y tercera ejecución también deberían 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
- ¿Funciona CommandBehavior.CloseConnection? (¿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
- Artículo sobre agrupación de conexiones
- Aquí hay otro que nos dice que Close () realmente no cierra la conexión.
- Un artículo sobre la combinación de conexiones de pros y contras
En general, desea que el grupo de conexiones haga su trabajo; no desea que la conexión realmente se cierre.
¿Por qué específicamente desea que la conexión no regrese al grupo?
La respuesta de Moe Sisko (llamada SqlConnection.ClearPool
) es correcta.
A veces necesitas una conexión para cerrar realmente en lugar de volver al grupo. 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 esta página en la agrupación de conexiones de SQL Server 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 a SqlConnection.ClearPool(connection)
antes de cerrar / desechar, cuando lo cierre / elimine realmente desaparecerá.
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.
Si no desea usar el grupo de conexiones, debe especificarlo en su propiedad SqlConnection.ConnectionString
. Por ejemplo
"Data Source=MSSQL1;Database=AdventureWorks;Integrated Security=true;Pooling=false;"
La eliminación o cierre del objeto SqlConnection
simplemente cerrará la conexión y la devolverá al grupo de conexiones.
Tal vez SqlConnection.ClearPool
?
CommandBehavior.CloseConnection
generalmente se desaconseja por este mismo hecho: no puede estar seguro de que Connection se cerrará. (Trataré de encontrar alguna evidencia concreta de esto, lo digo por un recuerdo débil).
Dispose()
es la forma más segura porque implícitamente llama a Close()
.
El constructo de using
demostrado por @Alex es simplemente otra forma (amigable con el programador) de escribir el constructo try-finally
con la eliminación implícita de objetos añadida.
Editar: (después de editar para preguntar)
Su preocupación por las conexiones que realmente se cierran me parece injustificada. 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.