Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
SqlConnectionrepresenta uma conexão lógica para o SQL Server, Banco de Dados SQL do Azure, Instância Gerenciada de SQL do Azure ou banco de dados SQL no Microsoft Fabric. Ao abrir o objeto, obtém-se uma conexão física do pool de conexões quando houver uma disponível. Fechá-la ou descartá-la retorna essa conexão física ao pool.
Use objetos de curta duração SqlConnection para unidades de trabalho. Não mantenha uma conexão global aberta para a aplicação.
Prerequisites
- O SDK .NET 10 ou um SDK do .NET posterior com suporte. O SDK roda no Windows, Linux e macOS. Também constrói a versão do .NET Framework de cada exemplo, que roda apenas no Windows e precisa do .NET Framework 4.8.1.
- Um banco de dados ao qual você pode se conectar no SQL Server, Banco de Dados SQL do Azure, Instância Gerenciada de SQL do Azure ou banco de dados SQL no Microsoft Fabric.
Criar o projeto
Microsoft. Data.SqlClient 7.0 e versões posteriores precisam do pacote de versão compatível Microsoft.Data.SqlClient.Extensions.Azure para modos de autenticação Microsoft Entra ID fornecidos por drivers, como Active Directory Default. Se seu aplicativo usa apenas autenticação SQL ou autenticação integrada ao Windows, você pode omitir isso.
Em uma pasta vazia, execute estes comandos:
dotnet new console --framework net10.0 --name SqlClientConnect
cd SqlClientConnect
dotnet add package Microsoft.Data.SqlClient --version 7.1.1
dotnet add package Microsoft.Data.SqlClient.Extensions.Azure --version 7.1.1
Os exemplos neste artigo leem a cadeia de conexão da variável de ambiente SQL_CONNECTION_STRING. Ajuste isso antes de executar um exemplo. Para formatos de cadeia de conexão, veja Connection strings.
Toda amostra, exceto a amostra de transação, é um programa completo. Para rodar um, substitua o conteúdo de Program.cs por ele e então execute dotnet run. O exemplo de transação é um fragmento para o seu método. A aba .NET usa instruções de nível superior, diretivas implícitas de using e await using. A guia .NET Framework usa C# 7.3, que não tem await using; então, ela usa instruções using.
Abra uma conexão
Chame OpenAsync em código assíncrono ou Open em código síncrono. Declare a conexão com await using ou using para que ela seja liberada quando o código sair do escopo, mesmo quando uma exceção for lançada.
Com a autenticação integrada ao Windows, a conexão usa a identidade do processo. Para um aplicativo web ou serviço Windows, esse é o pool de aplicações ou conta de serviço, não o usuário logado. Para mais informações, veja Escolher um padrão de autenticação.
Esse programa completo abre uma conexão, reporta cada mudança de estado e lê duas propriedades do servidor:
using Microsoft.Data.SqlClient;
string connectionString =
Environment.GetEnvironmentVariable("SQL_CONNECTION_STRING")
?? throw new InvalidOperationException(
"Set the SQL_CONNECTION_STRING environment variable.");
await using var connection = new SqlConnection(connectionString);
connection.StateChange += (_, e) =>
Console.WriteLine($"State: {e.OriginalState} to {e.CurrentState}");
await connection.OpenAsync();
await using var command = new SqlCommand(
"""
SELECT CAST(SERVERPROPERTY('Edition') AS nvarchar(128)),
CAST(SERVERPROPERTY('EngineEdition') AS int);
""",
connection);
await using (SqlDataReader reader = await command.ExecuteReaderAsync())
{
await reader.ReadAsync();
Console.WriteLine($"Edition: {reader.GetString(0)}");
Console.WriteLine($"EngineEdition: {reader.GetInt32(1)}");
}
Em comparação com a edição Enterprise 2025 do SQL Server, o resultado é:
State: Closed to Open
Edition: Enterprise Edition: Core-based Licensing (64-bit)
EngineEdition: 3
State: Open to Closed
A última linha aparece quando a conexão é descartada ao final do programa.
Fechar e descartar conexões
Sempre feche uma conexão quando terminar de usá-la para que a conexão física volte para o pool de conexões. As instruções using e await using descartam a conexão quando o código sai do bloco, inclusive quando uma exceção não tratada é lançada. Você também pode ligar diretamente para Close ou Dispose.
Close e Dispose têm o mesmo efeito na conexão física.
Siga estas regras:
- Descarte os leitores e os comandos antes da conexão à qual estão associados.
- Não confie na coleta de lixo para devolver uma conexão ao pool. Uma conexão que sai do escopo sem ser fechada não é retornada prontamente, e o pool pode ficar sem conexões.
- Não chame
CloseouDisposeem uma conexão, um leitor ou qualquer outro objeto gerenciado em um finalizador de classe. Um finalizador deve liberar apenas recursos não gerenciados que sua classe possui diretamente. Para saber mais, confira Coleta de lixo. - Após
Close, você pode chamarOpennovamente no mesmo objeto. ApósDispose, crie um novo objeto.
Com o pooling ativado, fechar uma conexão a devolve ao pool sem fechar a conexão de rede. O pool reinicia o estado da sessão quando a conexão é reutilizada. Para mais informações, veja SQL Server connection pooling.
Usar APIs assíncronas
Use chamadas assíncronas para trabalho de banco de dados vinculado à rede em servidores web, serviços, interfaces de usuário e trabalhadores:
OpenAsync(cancellationToken)ExecuteNonQueryAsync(cancellationToken)ExecuteReaderAsync(cancellationToken)ExecuteScalarAsync(cancellationToken)ReadAsync(cancellationToken)
Não inicie outra operação em uma conexão, comando ou leitor antes que a operação assíncrona atual termine.
Aplicar cancelamento e tempos limite
Passe o CancellationToken do chamador em todas as chamadas assíncronas ao banco de dados. O cancelamento pede ao driver que pare o trabalho pendente, mas a conclusão não é necessariamente imediata. Continue usando os tempos limite de conexão e de comando.
Esses controles possuem escopos separados:
| Controle | Scope |
|---|---|
Connect Timeout |
Estabelecimento de conexão, ou a espera por uma conexão do pool |
SqlCommand.CommandTimeout |
Execução de um comando |
CancellationToken |
Cancelamento solicitado pelo chamador de uma operação assíncrona |
Um tempo limite ou cancelamento não prova que o servidor reverteu uma operação. Use uma transação quando várias alterações precisarem ser confirmadas ou revertidas como uma única unidade, e tome decisões sobre nova tentativa com base na idempotência da operação e no resultado da transação.
Rastrear estado da conexão
A State propriedade retorna um snapshot da ConnectionState enumeração.
| State | Meaning |
|---|---|
Closed |
A conexão lógica não está aberta. |
Connecting |
Uma operação aberta está em andamento. |
Open |
A conexão lógica está aberta. |
O StateChange evento é ativado quando o estado muda. Seu StateChangeEventArgs argumento tem duas propriedades:
-
OriginalStateé o estado antes da mudança. -
CurrentStateé o estado após a mudança.
O driver relata as transições de Closed para Open e de Open para Closed, conforme mostra o exemplo em Abrir uma conexão. Não dependa de tratar Executing, Fetching ou Broken como fases do ciclo de vida do aplicativo.
Não use State como checagem de saúde antes de cada comando. A rede pode falhar após qualquer verificação. Execute a operação e trate da exceção resultante. Use StateChange para diagnóstico, não para coordenar o trabalho simultâneo.
Receber mensagens informativas
O InfoMessage evento entrega mensagens que o servidor envia sem gerar erro. Essas mensagens incluem PRINT saída, RAISERROR mensagens com gravidade 10 ou menor e avisos de servidor. Erros com gravidade de 11 ou superior geram um SqlException. Para os níveis de gravidade, veja severidades de erro do Mecanismo de Banco de Dados.
O gerenciador de eventos recebe um SqlInfoMessageEventArgs objeto. Sua Errors propriedade contém uma coleção de SqlError objetos. Cada um inclui o número da mensagem, texto, classe de gravidade, procedimento e número da linha.
using Microsoft.Data.SqlClient;
string connectionString =
Environment.GetEnvironmentVariable("SQL_CONNECTION_STRING")
?? throw new InvalidOperationException(
"Set the SQL_CONNECTION_STRING environment variable.");
await using var connection = new SqlConnection(connectionString);
connection.InfoMessage += (_, e) =>
{
foreach (SqlError error in e.Errors)
{
Console.WriteLine(
$"Message {error.Number}, severity {error.Class}: {error.Message}");
}
};
await connection.OpenAsync();
await using var command = new SqlCommand(
"""
PRINT 'Starting the batch.';
RAISERROR('Processed %d rows.', 10, 1, 42);
""",
connection);
await command.ExecuteNonQueryAsync();
A saída é:
Message 0, severity 0: Starting the batch.
Message 50000, severity 0: Processed 42 rows.
O servidor reporta uma RAISERROR gravidade de 10 como classe 0, então SqlError.Class aparece 0 para ambas as mensagens.
Lidar com erros do usuário como mensagens informativas
Por padrão, o driver reporta um erro com gravidade de 11 ou mais ao lançar um SqlException. Essa exceção não significa que o servidor interrompeu o lote. Muitos erros, inclusive RAISERROR com gravidade de 16, permitem que o servidor execute as instruções restantes, então instruções posteriores podem alterar dados mesmo quando seu código captura a exceção. Para receber esses erros como mensagens em vez de exceções, defina FireInfoMessageEventOnUserErrors para true. O driver envia erros com gravidade 16 ou inferior para o evento InfoMessage, em vez de lançá-los. Essa propriedade altera a forma como o driver reporta erros. Isso não muda quais instruções o servidor executa.
using Microsoft.Data.SqlClient;
string connectionString =
Environment.GetEnvironmentVariable("SQL_CONNECTION_STRING")
?? throw new InvalidOperationException(
"Set the SQL_CONNECTION_STRING environment variable.");
await using var connection = new SqlConnection(connectionString)
{
FireInfoMessageEventOnUserErrors = true,
};
connection.InfoMessage += (_, e) =>
{
foreach (SqlError error in e.Errors)
{
Console.WriteLine(
$"Message {error.Number}, severity {error.Class}: {error.Message}");
}
};
await connection.OpenAsync();
await using var command = new SqlCommand(
"""
RAISERROR('Row 7 failed validation.', 16, 1);
SELECT 'The batch continued.';
""",
connection);
await using (SqlDataReader reader = await command.ExecuteReaderAsync())
{
do
{
while (await reader.ReadAsync())
{
Console.WriteLine(reader.GetString(0));
}
}
while (await reader.NextResultAsync());
}
A saída é:
Message 50000, severity 16: Row 7 failed validation.
The batch continued.
Erros com gravidade de 17 ou mais ainda geram um SqlException, independentemente dessa configuração. Quando você ativa essa propriedade, seu handler é responsável por detectar falhas. Código que espera uma exceção para cada erro não vê uma.
Informe a identidade da aplicação
Começando pelo Microsoft.Data.SqlClient 7.1.0, um framework, ferramenta ou outro middleware pode informar qual aplicação abriu uma conexão. Defina RegisteredApplication para um RegisteredApplication valor antes de abrir a conexão. O driver envia o valor para o servidor uma vez, durante o login.
Siga estas regras:
- Defina o valor através da propriedade. Não existe palavra-chave da cadeia de conexão para ele.
- Defina o valor antes de abrir a conexão. Configurá-la enquanto a conexão está abrindo ou aberta gera um InvalidOperationException.
- Trate o valor como telemetria. O cliente fornece o valor e pode reportar qualquer identificador, então o servidor não o autentica.
- Espere que conexões agrupadas reportem a identidade original. O valor não faz parte da chave do pool. Uma conexão servida pelo pool relata a identidade da conexão lógica que causou a criação da conexão física.
Caution
Nunca use RegisteredApplication para autorização ou qualquer outra decisão de segurança. Qualquer cliente pode informar qualquer identificador.
Escolha um identificador
O valor padrão é Unknown, que é 0. A enumeração possui um tipo subjacente de ushort, então os identificadores variam de 0 até 0xFFFF.
| Intervalo | Usar |
|---|---|
0x0001 a 0x7FFF |
Aplicativos definidos pela Microsoft. Membros nomeados da enumeração usam essa faixa. |
0x8000 a 0xBFFF |
Reservado para uso em pequena escala. |
0xC000 a 0xFFFF |
Uso público e para desenvolvedores. |
Os membros nomeados são EntityFrameworkCore, SemanticKernel, ManagementStudio, SqlManagementObjects, DataTierApplicationFramework, SqlToolsService, AspNetCoreDistributedSqlServerCache, EntityFramework, AzureFunctionsSqlExtension, SqlPackage, OrleansAdoNet, DurableTaskSqlServer e DataApiBuilder. Para relatar um identificador sem um membro nomeado, converta o número em RegisteredApplication.
O RegisteredApplication tipo e a propriedade não são compatíveis com CLS porque a enumeração usa ushort. O código C# pode usá-los diretamente.
Defina o identificador
Este programa reporta um identificador do intervalo do desenvolvedor e então mostra o que acontece quando o código altera o valor após a abertura da conexão:
using Microsoft.Data.SqlClient;
string connectionString =
Environment.GetEnvironmentVariable("SQL_CONNECTION_STRING")
?? throw new InvalidOperationException(
"Set the SQL_CONNECTION_STRING environment variable.");
await using var connection = new SqlConnection(connectionString)
{
RegisteredApplication = (RegisteredApplication)0xC001,
};
await connection.OpenAsync();
Console.WriteLine(
$"Reported identifier: 0x{(ushort)connection.RegisteredApplication:X4}");
try
{
connection.RegisteredApplication = RegisteredApplication.Unknown;
}
catch (InvalidOperationException ex)
{
Console.WriteLine($"{ex.GetType().Name}: {ex.Message}");
}
A saída é:
Reported identifier: 0xC001
InvalidOperationException: Not allowed to change the 'RegisteredApplication' property. The connection's current state is open.
Entenda os efeitos do pooling
O driver só informa o identificador quando ele cria uma nova conexão física. Com pooling ativado:
- Uma conexão que reutiliza uma conexão física em pool reporta a identidade da conexão que criou a conexão física, não a dela própria.
- Conexões físicas que o pool abre em segundo plano para atender ao relatório
Min Pool SizeUnknown.
Se uma cadeia de conexão serve a várias identidades, trate o valor reportado como aproximado. Desative o pooling para essa cadeia de conexão quando precisar de atribuição exata e meça primeiro o custo extra da conexão.
SqlConnection.Clone Copia o RegisteredApplication valor para a nova conexão.
Não compartilhe uma conexão ao mesmo tempo
SqlConnection, SqlCommand, SqlDataReader, e SqlTransaction não suportam uso simultâneo por múltiplas threads. Dê a cada operação concorrente sua própria conexão e permita que o pool de conexões reutilize as conexões físicas.
Múltiplos Conjuntos de Resultados Ativos (MARS) permitem múltiplos lotes ativos em uma única conexão em cenários suportados. Isso não torna os objetos SqlClient seguros para threads, e adiciona regras de sessão e transação. Deixe-o desativado, a menos que uma operação precise especificamente.
Não registre um genérico aberto SqlConnection como singleton na injeção de dependências. Registre a cadeia de conexão, um objeto de opções imutável ou uma fábrica que cria uma nova conexão.
Use transações com critério
Uma transação local pertence à sua conexão. Todo comando na transação deve usar essa conexão e definir sua Transaction propriedade.
await using var connection = new SqlConnection(connectionString);
await connection.OpenAsync(cancellationToken);
await using SqlTransaction transaction =
(SqlTransaction)await connection.BeginTransactionAsync(cancellationToken);
using var command = new SqlCommand(sql, connection, transaction);
command.Parameters.Add(
new SqlParameter("@value", SqlDbType.Int) { Value = value });
await command.ExecuteNonQueryAsync(cancellationToken);
await transaction.CommitAsync(cancellationToken);
Se a operação falhar antes do commit, descartar a transação faz com que ela seja revertida. Mantenha as transações curtas. Não faça chamadas de rede, interação com usuários ou cálculos não relacionados enquanto uma transação de banco de dados mantém bloqueios.
Quando System.Transactions.Transaction.Current estiver ativado, Open e OpenAsync serão automaticamente inscritos por padrão. Definido Enlist=false apenas quando a operação deve permanecer fora da transação ambiente.
Medir uma conexão lógica
Defina StatisticsEnabled para true coletar estatísticas do driver para um SqlConnection objeto:
using System.Collections;
using Microsoft.Data.SqlClient;
string connectionString =
Environment.GetEnvironmentVariable("SQL_CONNECTION_STRING")
?? throw new InvalidOperationException(
"Set the SQL_CONNECTION_STRING environment variable.");
await using var connection = new SqlConnection(connectionString)
{
StatisticsEnabled = true,
};
await connection.OpenAsync();
connection.ResetStatistics();
await using var command = new SqlCommand("SELECT name FROM sys.databases;", connection);
await using (SqlDataReader reader = await command.ExecuteReaderAsync())
{
while (await reader.ReadAsync())
{
}
}
IDictionary statistics = connection.RetrieveStatistics();
Console.WriteLine($"ServerRoundtrips: {statistics["ServerRoundtrips"]}");
Console.WriteLine($"SelectRows: {statistics["SelectRows"]}");
Console.WriteLine($"BytesReceived > 0: {(long)statistics["BytesReceived"]! > 0}");
A saída mostra uma viagem de ida e volta. A contagem de linhas depende do número de bancos de dados no servidor:
ServerRoundtrips: 1
SelectRows: 14
BytesReceived > 0: True
RetrieveStatistics retorna um snapshot.
ResetStatistics Inicia uma nova fronteira de medição. Defina StatisticsEnabled como false para parar de coletar. Os valores coletados até agora ainda estão disponíveis. As estatísticas são específicas de cada objeto de conexão e geram sobrecarga; portanto, ative-as para diagnósticos direcionados em vez de ativá-las em todas as solicitações de produção.
Tratar falhas de conexão
Capture SqlException em um limite que possa registrar, traduzir ou repetir a falha. Registro:
NumberStateClassClientConnectionId- O nome da operação e identificadores de servidor e banco de dados configurados
Não registre a cadeia de conexão, a senha, o segredo do cliente nem o token de acesso.
Descarte uma conexão interrompida. O pool remove conexões físicas inválidas quando as detecta. Se uma credencial, token, certificado, destino DNS ou servidor for alterado, corrija a configuração antes de tentar novamente.
Use lógica de repetição limitada apenas para falhas transitórias. A nova tentativa na abertura inicial, a recuperação de conexão ociosa e a nova tentativa de comando são mecanismos diferentes. Para mais informações, veja Lógica de retentativa configurável e as opções de recuperação de conexão em Opções de conexão.