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.
- Artigo anterior: Etapa 3: prova de conceito da conexão ao SQL usando ADO.NET
Este artigo apresenta um exemplo de código em C# que demonstra uma lógica de repetição implementada manualmente. A lógica de repetição lida com erros temporários, ou falhas transitórias, que podem ser resolvidos se o programa aguardar e tentar realizar a operação novamente.
Importante
Para novos aplicativos que usam o Microsoft.Data.SqlClient 3.0 e versões posteriores, prefira a lógica de repetição configurável do driver em vez de implementar um loop de repetição. Comece com Configurar a lógica de nova tentativa no SqlClient.
As fontes de falhas transitórias incluem:
- Uma breve falha da rede que suporta a Internet.
- Um sistema em nuvem pode estar balanceando seus recursos quando sua consulta chega.
As classes ADO.NET para conexão ao SQL Server também podem se conectar ao Banco de Dados SQL do Azure. Seu programa cliente pode enfrentar falhas transitórias. A recuperação deve ocorrer utilizando uma política de nova tentativa limitada, adequada à operação.
Etapa 1: Identificar erros transitórios
Seu programa deve distinguir entre erros transitórios e erros persistentes. Erros transitórios são condições de erro que podem se resolver em pouco tempo, como problemas de rede transitória. Um exemplo de erro persistente é uma grafia errada no nome do banco de dados de destino. Nesse caso, o erro "Nenhum banco de dados encontrado desse tipo" persiste e não desaparece rapidamente.
A lista de números de erro categorizados como falhas transitórias está disponível em Mensagens de erro para aplicações cliente de banco de dados SQL.
Etapa 2: Criar e executar o aplicativo de exemplo
Este exemplo pressupõe que o .NET Framework 4.6.2 ou posterior esteja instalado. O exemplo de código C# consiste em um arquivo chamado Program.cs. Seu código é fornecido na próxima seção.
Etapa 2.a: Capturar e compilar o exemplo de código
Você pode compilar o exemplo com as seguintes etapas:
Na edição gratuita do Visual Studio Community, crie um novo projeto no modelo de Aplicativo do Console do C#.
Selecione Arquivo>Novo>>>Modelos>Visual C#>Windows>Área de Trabalho Clássica>Aplicativo de Console.
Dê ao projeto o nome de
RetryAdo2.
Abra o painel do Gerenciador de Soluções.
- Veja o nome do seu projeto.
- Em seu projeto, adicione uma dependência NuGet no pacote Microsoft.Data.SqlClient.
- Veja o nome do
Program.csarquivo.
Abra o arquivo
Program.cs.Substitua todo o conteúdo do
Program.csarquivo pelo código do bloco de código a seguir.Selecione o menu Build>Build Solution.
Etapa 2.b: Copiar e colar código de exemplo
Cole esse código no seu Program.cs arquivo.
Depois, edite as strings do nome do servidor e senha. Você pode encontrar essas cadeias no método chamado GetSqlConnectionString.
Observação
A cadeia de conexão é voltada para o Banco de Dados SQL do Azure, pois inclui o prefixo tcp:de quatro caracteres . Mas você pode ajustar a string do servidor para conectar à sua instância do SQL Server.
using System;
using System.Collections.Generic;
using Microsoft.Data.SqlClient;
using System.Threading;
namespace RetryAdo2;
public class Program
{
public static int Main(string[] args)
{
bool succeeded = false;
const int totalNumberOfTimesToTry = 4;
int retryIntervalSeconds = 10;
for (int tries = 1; tries <= totalNumberOfTimesToTry; tries++)
{
try
{
if (tries > 1)
{
Console.WriteLine(
"Transient error encountered. Will begin attempt number {0} of {1} max...",
tries,
totalNumberOfTimesToTry
);
Thread.Sleep(1000 * retryIntervalSeconds);
retryIntervalSeconds = Convert.ToInt32(retryIntervalSeconds * 1.5);
}
AccessDatabase();
succeeded = true;
break;
}
catch (SqlException sqlExc) {
if (TransientErrorNumbers.Contains(sqlExc.Number))
{
Console.WriteLine("{0}: transient occurred.", sqlExc.Number);
continue;
}
Console.WriteLine(sqlExc);
break;
}
catch (TestSqlException sqlExc) {
if (TransientErrorNumbers.Contains(sqlExc.Number))
{
Console.WriteLine("{0}: transient occurred. (TESTING.)", sqlExc.Number);
continue;
}
Console.WriteLine(sqlExc);
break;
}
catch (Exception e)
{
Console.WriteLine(e);
break;
}
}
if (!succeeded) {
Console.WriteLine("ERROR: Unable to access the database!");
return 1;
}
return 0;
}
/// <summary>
/// Connects to the database, reads,
/// prints results to the console.
/// </summary>
static void AccessDatabase() {
//throw new TestSqlException(4060); //(7654321); // Uncomment for testing.
using var sqlConnection = new SqlConnection(GetSqlConnectionString());
using var dbCommand = sqlConnection.CreateCommand();
dbCommand.CommandText = @"
SELECT TOP 3
ob.name,
CAST(ob.object_id as NVARCHAR(32)) AS [object_id]
FROM sys.objects AS ob
WHERE ob.type='IT'
ORDER BY ob.name;";
sqlConnection.Open();
var dataReader = dbCommand.ExecuteReader();
while (dataReader.Read())
{
Console.WriteLine(
"{0}\t{1}",
dataReader.GetString(0),
dataReader.GetString(1)
);
}
}
/// <summary>
/// Edit the four string values in accordance with your environment.
/// </summary>
/// <returns>An ADO.NET connection string.</returns>
static private string GetSqlConnectionString()
{
// Prepare the connection string to Azure SQL Database.
var sqlConnectionSB = new SqlConnectionStringBuilder
{
// Change these values to your values.
DataSource = "tcp:myazuresqldbserver.database.windows.net,1433", //["Server"]
InitialCatalog = "MyDatabase", //["Database"]
UserID = "MyLogin", // "@yourservername" as suffix sometimes.
Password = "<password>",
// Adjust these values if you like. (ADO.NET 4.5.1 or later.)
ConnectRetryCount = 3,
ConnectRetryInterval = 10, // Seconds.
// Leave these values as they are.
IntegratedSecurity = false,
Encrypt = true,
ConnectTimeout = 30
};
return sqlConnectionSB.ToString();
}
static List<int> TransientErrorNumbers = new()
{
4060, 40197, 40501, 40613, 49918, 49919, 49920, 11001
};
}
/// <summary>
/// For testing retry logic, you can have method
/// AccessDatabase start by throwing a new
/// TestSqlException with a Number that does
/// or does not match a transient error number
/// present in TransientErrorNumbers.
/// </summary>
internal class TestSqlException : ApplicationException
{
internal TestSqlException(int testErrorNumber)
{
Number = testErrorNumber;
}
internal int Number { get; set; }
}
Etapa 2.c: Execute o programa
O RetryAdo2.exe executável não recebe parâmetros. Para executar o .exe:
- Abra uma janela de console na pasta onde você compilou o
RetryAdo2.exebinário. - Execute
RetryAdo2.exesem parâmetros de entrada.
database_firewall_rules_table 245575913
filestream_tombstone_2073058421 2073058421
filetable_updates_2105058535 2105058535
Etapa 3: Formas de testar sua lógica de nova tentativa
Você pode simular um erro transitório para testar sua lógica de nova tentativa de várias maneiras.
Etapa 3.a: Gerar uma exceção de teste
O exemplo de código inclui:
- Uma pequena segunda classe nomeada
TestSqlExceptioncom uma propriedade chamadaNumber. -
//throw new TestSqlException(4060);, que você pode remover o comentário.
Se você descomentar a instrução throw e recompilar, a próxima execução de RetryAdo2.exe produzirá algo semelhante ao seguinte.
[C:\VS15\RetryAdo2\RetryAdo2\bin\Debug\]
>> RetryAdo2.exe
4060: transient occurred. (TESTING.)
Transient error encountered. Will begin attempt number 2 of 4 max...
4060: transient occurred. (TESTING.)
Transient error encountered. Will begin attempt number 3 of 4 max...
4060: transient occurred. (TESTING.)
Transient error encountered. Will begin attempt number 4 of 4 max...
4060: transient occurred. (TESTING.)
ERROR: Unable to access the database!
[C:\VS15\RetryAdo2\RetryAdo2\bin\Debug\]
>>
Etapa 3.b: Teste novamente com um erro persistente
Para provar que o código lida corretamente com erros persistentes, execute novamente o teste anterior. Em vez de usar um número de erro transitório real como 4060, use o número fictício 7654321. O programa trata esse número como um erro persistente e ignora qualquer retentativa.
Etapa 3.c: Desconectar da rede
- Desconecte o computador cliente da rede.
- Em um computador desktop, desconecte o cabo de rede.
- Para um laptop, pressione a combinação de função das teclas para desativar o adaptador de rede.
- Inicie
RetryAdo2.exee espere o console exibir o primeiro erro transitório, provavelmente 11001. - Reconecte-se à rede, enquanto
RetryAdo2.execontinua funcionando. - Observe o console relatar o sucesso em uma nova tentativa subsequente.
Etapa 3.d: temporariamente digitar incorretamente o nome do servidor
- Adicione temporariamente 40615 como outro número de erro em
TransientErrorNumbers, e recompile. - Defina um ponto de interrupção na linha:
new QC.SqlConnectionStringBuilder(). - Use o recurso Editar e Continuar para propositalmente digitar o nome do servidor de maneira incorreta algumas linhas abaixo.
- Deixe o programa continuar em execução até voltar ao ponto de interrupção.
- O erro 40615 ocorre.
- Corrija o erro de ortografia.
- Deixe o programa ser executado e concluir com êxito.
- Remova o 40615 e recompile.