¿Cuál es la forma correcta de asegurar que una conexión SQL se cierre cuando se lanza una excepción?

StackOverflow https://stackoverflow.com/questions/141204

  •  02-07-2019
  •  | 
  •  

Pregunta

Utilizo un patrón que se ve algo así a menudo. Me pregunto si esto está bien o si hay una mejor práctica que no estoy aplicando aquí.

Específicamente me estoy preguntando; en el caso de que se produzca una excepción, ¿el código que tengo en el bloque finalmente es suficiente para garantizar que la conexión se cierre correctamente?

public class SomeDataClass : IDisposable
{
    private SqlConnection _conn;

    //constructors and methods

    private DoSomethingWithTheSqlConnection()
    {
        //some code excluded for brevity

        try
        {
            using (SqlCommand cmd = new SqlCommand(SqlQuery.CountSomething, _SqlConnection))
            {
                _SqlConnection.Open();
                countOfSomething = Convert.ToInt32(cmd.ExecuteScalar());
            }
        }
        finally
        {
            //is this the best way?
            if (_SqlConnection.State == ConnectionState.Closed)
                _SqlConnection.Close();
        }

        //some code excluded for brevity
    }

    public Dispose()
    {
        _conn.Dispose();
    }
}
¿Fue útil?

Solución

Envuelva el código de manejo de su base de datos dentro de " usando "

using (SqlConnection conn = new SqlConnection (...))
{
    // Whatever happens in here, the connection is 
    // disposed of (closed) at the end.
}

Otros consejos

.Net Framework mantiene un grupo de conexiones por una razón. ¡Confía en ello! :) No tiene que escribir tanto código solo para conectarse a la base de datos y liberar la conexión.

Puedes usar la declaración 'using' y puedes estar seguro de que 'IDBConnection.Release ()' cerrará la conexión por ti.

Las 'soluciones' altamente elaboradas tienden a dar como resultado un código con errores. Lo simple es mejor.

MSDN Docs haga esto bastante claro ...

  • El método Cerrar revierte cualquier transacción pendiente. A continuación, libera la conexión a la agrupación de conexiones o la cierra si la agrupación de conexiones está desactivada.

Probablemente no haya (y no quiera) deshabilitar la agrupación de conexiones, por lo que la agrupación en última instancia gestiona el estado de la conexión después de llamar " Cerrar " ;. Esto podría ser importante ya que puede estar confundido al mirar desde el lado del servidor de la base de datos todas las conexiones abiertas.


  • Una aplicación puede llamar a Cerrar más de una vez. No se genera ninguna excepción.

Entonces, ¿por qué molestarse en probar para Closed? Simplemente llama a Cerrar ().


  • Cerrar y Disponer son funcionalmente equivalentes.

Por esta razón, un bloque utilizando da como resultado una conexión cerrada. usar las llamadas, disponer por ti.


  • No llame a Cerrar o Desechar en una Conexión, un DataReader o cualquier otro objeto administrado en el método Finalize de su clase.

Importante consejo de seguridad. Gracias, Egon.

Supongo que por " _SqlConnection.State == ConnectionState.Closed " quiso decir! =.

Esto ciertamente funcionará. Creo que es más habitual contener el objeto de conexión dentro de una declaración de uso, pero lo que tienes es bueno si quieres reutilizar el mismo objeto de conexión por alguna razón.

Una cosa que definitivamente debes cambiar, sin embargo, es el método Dispose (). No debe hacer referencia al objeto de conexión en disposición, ya que puede que ya se haya finalizado en ese momento. Debes seguir el patrón de Disposición recomendado.

Ya que estás usando IDisposables de todos modos. Puede usar la palabra clave 'using', que es básicamente equivalente a llamar a disposición en un bloque finally, pero se ve mejor.

Vea esta pregunta para la respuesta:

Close and Disose - ¿a quién llamar?

Si la vida útil de su conexión es una llamada de un solo método, use la función using del idioma para garantizar la correcta limpieza de la conexión. Si bien un bloque try / finally es funcionalmente el mismo, requiere más código y IMO es menos legible. No hay necesidad de verificar el estado de la conexión, puede llamar a Dispose independientemente y se encargará de limpiar la conexión.

Si la vida útil de su conexión corresponde a la vida útil de una clase contenedora, entonces implemente IDisposable y limpie la conexión en Dispose .

Coloque el código de cierre de conexión dentro de un " Finalmente " Bloquea como tu muestras. Finalmente los bloques se ejecutan antes de que se lance la excepción. Usando un " usando " el bloque funciona igual de bien, pero me parece explícito " Finalmente " Método más claro.

El uso de los enunciados es antiguo para muchos desarrolladores, pero los desarrolladores más jóvenes pueden no saberlo de antemano.

no es necesario que intente ... finalmente alrededor de " usando " ;, el uso de ES es un intento..finalmente

Puedo sugerir esto:


    class SqlOpener : IDisposable
    {
        SqlConnection _connection;

        public SqlOpener(SqlConnection connection)
        {
            _connection = connection;
            _connection.Open();

        }

        void IDisposable.Dispose()
        {
            _connection.Close();
        }
    }

    public class SomeDataClass : IDisposable
    {
        private SqlConnection _conn;

        //constructors and methods

        private void DoSomethingWithTheSqlConnection()
        {
            //some code excluded for brevity
            using (SqlCommand cmd = new SqlCommand("some sql query", _conn))
            using(new SqlOpener(_conn))
            {
                int countOfSomething = Convert.ToInt32(cmd.ExecuteScalar());
            }
            //some code excluded for brevity
        }

        public void Dispose()
        {
            _conn.Dispose();
        }
    }

Espero que ayude :)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top