¿"Abrir / cerrar" SqlConnection o mantener abierto?

121

Tengo mi lógica empresarial implementada en clases estáticas simples con métodos estáticos. Cada uno de estos métodos abre / cierra la conexión SQL cuando se llama:

public static void DoSomething(string something)
{
    using (SqlConnection connection = new SqlConnection("..."))
    {
        connection.Open();

        // ...

        connection.Close();
    }
}

Pero creo que evitar abrir y cerrar una conexión ahorra rendimiento . Hice algunas pruebas hace mucho tiempo con la clase OleDbConnection (no estoy seguro sobre SqlConnection), y definitivamente ayudó a trabajar así (por lo que recuerdo):

//pass the connection object into the method
public static void DoSomething(string something, SqlConnection connection)
{
    bool openConn = (connection.State == ConnectionState.Open);
    if (!openConn)
    {
        connection.Open();
    }

    // ....

    if (openConn) 
    {
        connection.Close();
    }
}

Entonces la pregunta es: ¿debo elegir el método (a) o el método (b)? Leí en otra pregunta de stackoverflow que la agrupación de conexiones me ahorró rendimiento, no tengo que molestarme en absoluto ...

PD. Es una aplicación ASP.NET: las conexiones solo existen durante una solicitud web. No es una aplicación o un servicio para ganar.

Alex
fuente
1
Solo un consejo: use el DbConnection.StateChangeevento para monitorear los cambios en el cambio de estado de la conexión (y puede almacenarse localmente) en lugar de verificar la DbConnection.Statepropiedad directamente. Le ahorrará costes de rendimiento.
Deciclón
1
Un detalle que falta es cómo este método es parte de una solicitud de página. ¿Es el único método llamado o es, como asumí en mi respuesta, uno de los muchos métodos que se llama en una página solicitada, afecta qué respuesta es correcta?)
David Mårtensson
David - un montón de métodos de este tipo están siendo llamados :)
Alex
1
El caso A muestra una falta de fe en Dispose: consulte stackoverflow.com/questions/1195829/… y el ejemplo en MSDN msdn.microsoft.com/en-us/library/…
user2864740

Respuestas:

82

Apégate a la opción a .

La agrupación de conexiones es tu amiga.

Adriaan Stander
fuente
37
En mi humilde opinión, ni siquiera debería acercarse. la disposición lo hará.
Royi Namir
2
@RoyiNamir Me gusta un poco la llamada para cerrar la conexión. Especialmente para principiantes y recién llegados a una base de código. Es más explícito y legible.
edhedges
27
@edhedges Utilizar tanto "using" y Close () en última instancia, solo causará confusión a los recién llegados. No van a entender el propósito de utilizar "usar". No use "Cerrar" en lugar de enseñarles el propósito de "usar". Para que puedan aprender, mejorar y aplicar lo que aprenden a otras partes del código.
Luis Perez
1
¿Se debe llamar a "Open ()"? Actualmente lo estoy usando así: using (var conn = GetConnection ()) {} public SqlConnection GetConnection () {return new SqlConnection (_connectionString); }
ganders
79

Utilice el método (a), siempre. Cuando comience a escalar su aplicación, la lógica que trata con el estado se convertirá en un verdadero problema si no lo hace.

La agrupación de conexiones hace lo que dice en la lata. Solo piense en lo que sucede cuando la aplicación escala y lo difícil que sería administrar manualmente el estado de apertura / cierre de la conexión. El grupo de conexiones hace un buen trabajo al manejar esto automáticamente. Si le preocupa el rendimiento, piense en algún tipo de mecanismo de memoria caché para que nada se bloquee.

WeNeedAnswers
fuente
33

Siempre cierre las conexiones tan pronto como haya terminado con ellas, para que la conexión de la base de datos subyacente pueda volver al grupo y estar disponible para otras personas que llaman. La agrupación de conexiones está bastante bien optimizada, por lo que no hay una penalización notable por hacerlo. El consejo es básicamente el mismo que para las transacciones: manténgalos breves y cerrados cuando haya terminado.

Se vuelve más complicado si se encuentra con problemas de MSDTC al usar una sola transacción en torno al código que usa múltiples conexiones, en cuyo caso realmente tiene que compartir el objeto de conexión y solo cerrarlo una vez que finaliza la transacción.

Sin embargo, está haciendo las cosas a mano aquí, por lo que es posible que desee investigar las herramientas que administran las conexiones por usted, como DataSets, Linq to SQL, Entity Framework o NHibernate.

Neil Barnwell
fuente
Normalmente, no debe abrir y cerrar una conexión dentro de cada llamada de método, solo una vez para cada solicitud de página. Eso es lo que he aprendido al menos;) Abrir y cerrar cuesta tiempo.
David Mårtensson
8
@David Martensson: las conexiones no se abren ni se cierran realmente cuando se llama a SqlConnection.Open. ASP.NET recicla las conexiones activas del grupo cuando la cadena de conexión coincide con una cadena de conexión utilizada anteriormente. La sobrecarga involucrada en esto es intrascendente y, además, tratar de "hacerlo usted mismo" significa que debe asumir todas las tareas de administración para garantizar que la conexión siga activa para cada uso posterior, lo que agrega complejidad y sobrecarga. Con la agrupación de conexiones, la mejor práctica es abrirla y cerrarla para cada uso.
Jamie Treworgy
2
Con todo mi respeto, la respuesta "Conexiones siempre cercanas" no encaja muy bien con la pregunta ... Yo sí las cierro. La pregunta es cuándo.
Alex
@David Martensson "Una vez por cada página" está muy simplificado. Tiene razón en que si tiene varios comandos de base de datos para ejecutar uno tras otro, puede mantener la conexión abierta mientras los ejecuta. Habría una sobrecarga menor si cerrara y volviera a abrir: la conexión entraría en el grupo y se recuperaría un momento después.
Concrete Gannet
1
@David Martensson Pero nunca mantenga una conexión inactiva. Si está esperando una acción del usuario o cualquier otra cosa, ciérrela. En caso de duda, ciérrelo. Abre tan tarde como puede con la esperanza de que alguien más haya terminado con una conexión y la haya agrupado. Luego devuelve el favor, cierre lo antes posible.
Concrete Gannet
13

Descargo de responsabilidad: sé que esto es antiguo, pero encontré una manera fácil de demostrar este hecho, así que estoy poniendo mis dos centavos.

Si tiene problemas para creer que la agrupación realmente va a ser más rápida, pruebe esto:

Agregue lo siguiente en algún lugar:

using System.Diagnostics;
public static class TestExtensions
{
    public static void TimedOpen(this SqlConnection conn)
    {
        Stopwatch sw = Stopwatch.StartNew();
        conn.Open();
        Console.WriteLine(sw.Elapsed);
    }
}

Ahora reemplace todas las llamadas a Open()con TimedOpen()y ejecute su programa. Ahora, para cada cadena de conexión distinta tenga, (salida) ventana de la consola tendrá un único larga duración abierta, y un montón de muy aperturas rápidas.

Si desea etiquetarlos, puede agregarlos new StackTrace(true).GetFrame(1) +a la llamada WriteLine.

Chris Pfohl
fuente
9

Hay distinciones entre conexiones físicas y lógicas. DbConnection es un tipo de conexión lógica y utiliza una conexión física subyacente a Oracle. Cerrar / abrir DbConnection no afecta su rendimiento, pero hace que su código sea limpio y estable; en este caso, las fugas de conexión son imposibles.

También debe recordar los casos en que existen limitaciones para las conexiones paralelas en el servidor de base de datos, teniendo en cuenta que es necesario hacer sus conexiones muy cortas.

El grupo de conexiones lo libera de la verificación del estado de la conexión: solo ábralos, úselos y ciérrelos inmediatamente.

Tony Kh
fuente
Sí, la conexión no es la conexión, es decir, DbConnection no es la conexión física. DbConnection es una clase .NET que proporciona métodos y propiedades para manipular la conexión física subyacente.
Concrete Gannet
Desafortunadamente, no fue inmediatamente obvio que todo esto se hizo de manera implícita, pero la documentación lo elabora. docs.microsoft.com/en-us/dotnet/framework/data/adonet/…
Austin Salgat
2

Normalmente, debe mantener una conexión para cada transacción (sin cálculos paralelos)

Por ejemplo, cuando el usuario ejecuta una acción de carga, su aplicación necesita buscar primero el saldo del usuario y actualizarlo, deben usar la misma conexión.

Incluso si ado.net tiene su grupo de conexiones, el costo de envío de la conexión es muy bajo, pero reutilizar la conexión es una mejor opción.

¿Por qué no mantener una sola conexión en la aplicación?

Debido a que la conexión se bloquea cuando ejecuta alguna consulta o comando, eso significa que su aplicación solo está haciendo una operación de base de datos al mismo tiempo, qué bajo rendimiento es.

Un problema más es que su aplicación siempre tendrá una conexión a pesar de que su usuario simplemente la abre pero no hay operaciones. Si hay muchos usuarios que abren su aplicación, el servidor db costará toda su fuente de conexión pronto, mientras que sus usuarios no lo han hecho. cualquier cosa.

ShiningRush
fuente