O que é a maneira correta para garantir uma conexão SQL é fechado quando uma exceção é lançada?

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

  •  02-07-2019
  •  | 
  •  

Pergunta

Eu uso um padrão que é algo como isto muitas vezes. Eu estou querendo saber se isso é certo ou se não é uma prática recomendada que não estou aplicando aqui.

Especificamente eu estou querendo saber; no caso em que uma exceção é lançada é o código que eu tenho no bloco finally suficiente para garantir que a conexão é fechada adequadamente?

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();
    }
}
Foi útil?

Solução

Envolva seu código de manipulação de banco de dados dentro de um "usando"

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

Outras dicas

O .Net Framework mantains um pool de conexão por uma razão. Confia! :) Você não tem que escrever muito código apenas para se conectar ao banco de dados e libertar a ligação.

Você pode simplesmente usar o 'usando' declaração e tenha a certeza de que 'IDBConnection.Release ()' fecha a conexão para você.

'soluções' altamente elaborados tendem a resultar em código de buggy. Simples é melhor.

MSDN Docs fazer este bastante claro ...

  • As método close reverte quaisquer transações pendentes. Em seguida, ele libera a conexão com o pool de conexão, ou fecha a conexão se o pool de conexão está desativado.

Você provavelmente não tem (e não querem) desabilitar o pool de conexão, portanto, a piscina em última análise, controla o estado da conexão após chamar "Close". Isso pode ser importante, como você pode ser confundido olhando do lado do servidor de banco de dados em todas as conexões abertas.


  • Um aplicativo pode chamar Fechar mais de uma vez. Nenhuma exceção é gerada.

Então, por que se preocupar testes para Fechado? Basta ligar para Close ().


  • Feche e Descarte são funcionalmente equivalentes.

É por isso que um usando Resultados bloco em uma conexão fechada. usando chama Descarte para você.


  • Não chame Close ou Dispose em uma conexão, um DataReader, ou qualquer outro objeto gerenciado no método Finalize de sua classe.

dica de segurança importante. Obrigado, Egon.

Eu estou supondo que por "_SqlConnection.State == ConnectionState.Closed" você quis dizer! =.

Isso vai certamente funcionar. Eu acho que é mais habitual para conter o próprio objeto de conexão dentro de um usando declaração, mas o que você tem é bom se você quer reutilizar o mesmo objeto de conexão por algum motivo.

Uma coisa que você definitivamente deve mudar, no entanto, é o método Dispose (). Você não deve fazer referência o objeto de conexão em dispor, porque ele pode já ter sido finalizado naquele ponto. Você deve seguir o padrão Dispose recomendado vez.

Uma vez que você estiver usando IDisposables de qualquer maneira. Você pode usar o 'usando' palavra-chave, que é basicamente equivalente a chamar Dispose em um bloco, finalmente, mas parece melhor.

Veja esta pergunta para a resposta:

Feche e Descarte - qual o chamar

Se o seu tempo de vida de conexão é uma única chamada de método, utilize o recurso using da língua para garantir a limpeza adequada da conexão. Enquanto um bloco try/finally é funcionalmente o mesmo, requer mais código e IMO é menos legível. Não há necessidade de verificar o estado da conexão, você pode chamar Dispose independentemente e ele vai lidar com a limpeza-up da conexão.

Se a sua conexão corresponde vida para a vida de uma classe que contém, em seguida, implementar IDisposable e clean-up a conexão em Dispose.

Coloque o código estreita ligação dentro de um bloco "Finalmente", como você mostra. Finalmente blocos são executados antes a exceção é lançada. Usando um "usando" bloco funciona tão bem, mas acho que a explícita "Finalmente" método mais clara.

Usando declarações são chapéu velho para muitos desenvolvedores, mas os desenvolvedores mais jovens podem não saber que fora da mão.

há necessidade de um try..finally em torno de um "usando", o usando é a try..finally

Posso sugerir o seguinte:


    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 ajude:)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top