“Abrir / fechar” SqlConnection ou manter aberto?

121

Tenho minha lógica de negócios implementada em classes estáticas simples com métodos estáticos. Cada um desses métodos abre / fecha a conexão SQL quando chamado:

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

        // ...

        connection.Close();
    }
}

Mas acho que evitar abrir e fechar uma conexão economiza desempenho . Eu fiz alguns testes loooongo tempo atrás com a classe OleDbConnection (não tenho certeza sobre SqlConnection) e definitivamente ajudou a trabalhar assim (pelo que me lembro):

//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();
    }
}

Portanto, a questão é - devo escolher o método (a) ou método (b)? Eu li em outra questão de stackoverflow que o pool de conexão salvou o desempenho para mim, eu não tenho que me preocupar ...

PS. É um aplicativo ASP.NET - as conexões existem apenas durante uma solicitação da web. Não é um aplicativo ou serviço win.

Alex
fonte
1
Apenas um aviso: Use o DbConnection.StateChangeevento para monitorar as mudanças no estado da conexão (e pode ser armazenado localmente) em vez de verificar a DbConnection.Statepropriedade diretamente. Isso irá economizar custos de desempenho.
deciclone
1
Um detalhe que está faltando é como esse método faz parte de uma solicitação de página. É o único método chamado ou é, como assumi em minha resposta, um dos muitos métodos que é chamado em uma solicitação de página, que afeta a resposta certa;)
David Mårtensson
David - MUITOS métodos como este estão sendo chamados :)
Alex
1
O caso A mostra falta de confiança no Dispose: consulte stackoverflow.com/questions/1195829/… e o exemplo no MSDN msdn.microsoft.com/en-us/library/…
user2864740

Respostas:

82

Atenha-se à opção a .

O pool de conexão é seu amigo.

Adriaan Stander
fonte
37
IMHO - ele não deveria nem fechar. o descarte vai fazer isso.
Royi Namir
2
@RoyiNamir Eu meio que gosto da ligação para encerrar a conexão. Especialmente para iniciantes e novatos em uma base de código. É mais explícito e legível.
edhedges
27
@edhedges Utilizar "using" e Close () só vai causar confusão para os novatos. Eles não vão entender o propósito de utilizar "usando". Não use "Fechar" em vez disso, ensine a eles o propósito de "usar". Para que eles possam aprender, melhorar e aplicar o que aprenderam a outras partes do código.
Luis Perez,
1
Deve / deve ser chamado "Open ()"? Atualmente, estou usando assim: using (var conn = GetConnection ()) {} public SqlConnection GetConnection () {return new SqlConnection (_connectionString); }
ganders
79

Use o Método (a), todas as vezes. Quando você começa a dimensionar seu aplicativo, a lógica que lida com o estado se tornará uma verdadeira dor se você não fizer isso.

O pool de conexão faz o que diz na lata. Basta pensar no que acontece quando o aplicativo é dimensionado e como seria difícil gerenciar manualmente o estado de abertura / fechamento da conexão. O pool de conexão faz um bom trabalho em lidar com isso automaticamente. Se você está preocupado com o desempenho, pense em algum tipo de mecanismo de cache de memória para que nada seja bloqueado.

WeNeedAnswers
fonte
33

Sempre feche as conexões assim que terminar de usá-las, para que a conexão de banco de dados subjacente possa voltar para o pool e ficar disponível para outros chamadores. O pool de conexão é muito bem otimizado, portanto, não há nenhuma penalidade perceptível para fazer isso. O conselho é basicamente o mesmo que para as transações - mantenha-as curtas e feche quando terminar.

Fica mais complicado se você tiver problemas de MSDTC usando uma única transação em torno do código que usa várias conexões; nesse caso, você realmente precisa compartilhar o objeto de conexão e apenas fechá-lo quando a transação for concluída.

No entanto, você está fazendo as coisas manualmente aqui, então você pode querer investigar ferramentas que gerenciam conexões para você, como DataSets, Linq to SQL, Entity Framework ou NHibernate.

Neil Barnwell
fonte
Normalmente, você não deve abrir e fechar uma conexão em cada chamada de método, apenas uma vez para cada solicitação de página. Isso é o que eu aprendi pelo menos;) Tempo de custos de abertura e fechamento.
David Mårtensson
8
@David Martensson - as conexões não são realmente abertas e fechadas quando você chama SqlConnection.Open. O ASP.NET recicla conexões ativas do pool quando a string de conexão corresponde a uma string de conexão usada anteriormente. A sobrecarga envolvida nisso é irrelevante e, além disso, tentar "fazer você mesmo" significa que você deve assumir todas as tarefas de gerenciamento para garantir que a conexão ainda esteja ativa para cada uso subsequente, o que adiciona complexidade e sobrecarga. Com o pool de conexão, a prática recomendada é abri-lo e fechá-lo para cada uso.
Jamie Treworgy
2
Com todo o meu respeito, a resposta "Sempre fechar conexões" não se enquadra muito bem na pergunta ... Eu as fecho. A questão é - quando.
Alex
@David Martensson "Uma vez para cada página" é simplificado demais. Você está certo ao dizer que, se tiver vários comandos de banco de dados para executar um após o outro, poderá manter a conexão aberta enquanto os executa. Haveria uma pequena sobrecarga se você fechasse e reabrisse - a conexão iria para o pool e seria recuperada um momento depois.
Ganso de concreto
1
@David Martensson Mas nunca mantenha uma conexão ociosa. Se você estiver esperando por uma ação do usuário ou por qualquer outra coisa, feche-o. Em caso de dúvida, feche-o. Você abre o mais tarde possível, na esperança de que outra pessoa tenha encerrado a conexão e a tenha agrupado. Em seguida, você retribui o favor - feche o mais cedo possível.
Ganso de concreto
13

Isenção de responsabilidade: eu sei que isso é antigo, mas encontrei uma maneira fácil de demonstrar esse fato, então estou investindo meus dois centavos.

Se você está tendo problemas para acreditar que o pooling será realmente mais rápido, tente:

Adicione o seguinte em algum 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);
    }
}

Agora substitua todas as chamadas para Open()com TimedOpen()e executar o seu programa. Agora, para cada string de conexão distinta que você tiver, a janela do console (saída) terá uma única longa aberta e várias aberturas muito rápidas.

Se você quiser rotulá-los, poderá adicionar new StackTrace(true).GetFrame(1) +à chamada para WriteLine.

Chris Pfohl
fonte
9

Existem distinções entre conexões físicas e lógicas. DbConnection é um tipo de conexão lógica e usa uma conexão física subjacente ao Oracle. Fechar / abrir DbConnection não afeta seu desempenho, mas torna seu código limpo e estável - vazamentos de conexão são impossíveis neste caso.

Além disso, você deve se lembrar dos casos em que há limitações para conexões paralelas no servidor db - levando isso em consideração, é necessário fazer conexões muito curtas.

O conjunto de conexões libera você da verificação do estado da conexão - basta abri-los, usá-los e fechá-los imediatamente.

Tony Kh
fonte
Sim, a conexão não é a conexão - ou seja, DbConnection não é a conexão física. DbConnection é uma classe .NET que fornece métodos e propriedades para manipular a conexão física subjacente.
Ganso de concreto
Infelizmente, não foi imediatamente óbvio que isso foi feito de forma implícita, mas a documentação detalha isso. docs.microsoft.com/en-us/dotnet/framework/data/adonet/…
Austin Salgat
2

Normalmente você deve manter uma conexão para cada transação (sem cálculos paralelos)

por exemplo, quando o usuário executa a ação de cobrança, seu aplicativo precisa encontrar o saldo do usuário primeiro e atualizá-lo, eles devem usar a mesma conexão.

Mesmo se ado.net tiver seu pool de conexão, o custo de envio de conexão é muito baixo, mas reutilizar a conexão é a melhor escolha.

Por que não manter apenas uma conexão no aplicativo

Como a conexão está bloqueando quando você executa alguma consulta ou comando, isso significa que seu aplicativo está fazendo apenas uma operação de banco de dados por vez, o desempenho é ruim.

Mais um problema é que seu aplicativo sempre terá uma conexão, mesmo que seu usuário esteja apenas abrindo-o, mas sem operações. Se houver muitos usuários abrindo seu aplicativo, o servidor db irá custar toda a sua fonte de conexão em breve, enquanto seus usuários não o fizeram qualquer coisa.

ShiningRush
fonte