Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
- Poprzedni artykuł: Krok 3: Weryfikacja koncepcji nawiązywania połączenia z bazą danych SQL przy użyciu ADO.NET
Ten artykuł zawiera przykładowy kod w języku C#, który demonstruje niestandardową logikę ponawiania prób. Logika ponawiania prób zapewnia niezawodność. Logika ponawiania prób została zaprojektowana tak, aby bezpiecznie przetwarzać tymczasowe błędy lub błędy przejściowe, które mają tendencję do odejścia, jeśli program czeka kilka sekund i ponawia próbę.
Źródła błędów przejściowych obejmują:
- Krótka awaria sieci obsługującej Internet.
- System w chmurze może równoważyć obciążenie zasobów w momencie wysłania zapytania.
Klasy ADO.NET służące do nawiązywania połączenia z lokalnym programem Microsoft SQL Server mogą również łączyć się z usługą Azure SQL Database. Jednak samodzielnie klasy ADO.NET nie mogą zapewnić całej niezawodności i niezawodności niezbędnej do użycia w środowisku produkcyjnym. Program kliencki może napotkać błędy przejściowe, z których powinien cicho i elegancko się odnowić i kontynuować samodzielnie.
Krok 1. Identyfikowanie błędów przejściowych
Program musi rozróżniać błędy przejściowe w porównaniu z trwałymi błędami. Błędy przejściowe to rodzaje błędów, które mogą ustąpić po krótkim czasie, takie jak przejściowe problemy z siecią. Przykładem trwałego błędu może być błąd, jeśli program ma błędną pisownię docelowej nazwy bazy danych — w tym przypadku błąd "Nie znaleziono takiej bazy danych" będzie się powtarzać i nie ma szans na wyczyszczenie w krótkim czasie.
Lista numerów błędów sklasyfikowanych jako błędy przejściowe jest dostępna w komunikaty o błędach dla aplikacji klienckich usługi SQL Database
Krok 2. Tworzenie i uruchamianie przykładowej aplikacji
W tym przykładzie założono, że jest zainstalowany program .NET Framework 4.6.2 lub nowszy. Przykładowy kod języka C# składa się z jednego pliku o nazwie Program.cs. Jego kod jest udostępniany w następnej sekcji.
Krok 2.a. Przechwytywanie i kompilowanie przykładowego kodu
Przykład można skompilować, wykonując następujące kroki:
- W bezpłatnej wersji Visual Studio Community editionutwórz nowy projekt na podstawie szablonu aplikacji konsolowej języka C#.
- Plik > Nowy projekt >> Zainstalowane szablony >> Visual C# > Windows > Klasyczny pulpit > Aplikacja konsolowa
- Nadaj projektowi nazwę RetryAdo2.
- Otwórz okienko Eksplorator rozwiązań.
- Zobacz nazwę projektu.
- W projekcie dodać zależności NuGet w pakiecie Microsoft.Data.SqlClient.
- Zobacz nazwę pliku Program.cs.
- Otwórz plik Program.cs.
- Całkowicie zastąp zawartość pliku Program.cs kodem w poniższym bloku kodu.
- Wybierz z menu Kompiluj > kompiluj rozwiązanie.
Krok 2.b. Kopiowanie i wklejanie przykładowego kodu
Wklej ten kod do pliku Program.cs.
Następnie należy edytować ciągi dla nazwy serwera, hasła itd. Te ciągi można znaleźć w metodzie o nazwie GetSqlConnectionString.
Notatka
Parametry połączenia dla nazwy serwera są dostosowane do usługi Azure SQL Database, ponieważ zawierają czteroznakowy prefiks tcp:. Można jednak dostosować ciąg serwera, aby nawiązać połączenie z programem Microsoft 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; }
}
Krok 2.c. Uruchamianie programu
Dane wejściowe pliku wykonywalnego RetryAdo2.exe nie mają parametrów. Aby uruchomić .exe:
- Otwórz okno konsoli, w którym skompilujesz plik binarny RetryAdo2.exe.
- Uruchom RetryAdo2.exe, bez parametrów wejściowych.
database_firewall_rules_table 245575913
filestream_tombstone_2073058421 2073058421
filetable_updates_2105058535 2105058535
Krok 3. Sposoby testowania logiki ponawiania prób
Istnieje wiele sposobów symulowania błędu przejściowego w celu przetestowania logiki ponawiania prób.
Krok 3.a. Zgłaszanie wyjątku testowego
Przykładowy kod zawiera następujące elementy:
- Mała druga klasa o nazwie TestSqlExceptionz właściwością o nazwie Number.
-
//throw new TestSqlException(4060);, który można odkomentować.
Jeśli usuniesz komentarz z instrukcji throw i ponownie skompilujesz, następne uruchomienie RetryAdo2.exe wyświetli wynik podobny do poniższego.
[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\]
>>
Krok 3.b: Powtórne testowanie z utrzymującym się błędem
Aby udowodnić, że kod poprawnie obsługuje trwałe błędy, uruchom ponownie poprzedni test, z wyjątkiem nie używaj liczby rzeczywistego błędu przejściowego, takiego jak 4060. Zamiast tego należy użyć nonsensownego numeru 7654321. Program powinien traktować to jako trwały błąd i powinien pominąć wszelkie ponawianie próby.
Krok 3.c. Odłączanie od sieci
- Odłącz komputer kliencki od sieci.
- W przypadku komputera stacjonarnego odłącz kabel sieciowy.
- W przypadku laptopa naciśnij kombinację funkcji, aby wyłączyć kartę sieciową.
- Uruchom RetryAdo2.exei poczekaj, aż konsola wyświetli pierwszy błąd przejściowy, prawdopodobnie 11001.
- Podłącz się ponownie do sieci, podczas gdy RetryAdo2.exe nadal działa.
- Obserwuj raport konsoli, który potwierdzi sukces przy kolejnym ponowieniu.
Krok 3.d: Tymczasowo błędnie zapisz nazwę serwera
- Tymczasowo dodaj numer 40615 jako kolejny numer błędu do TransientErrorNumbersi ponownie skompiluj.
- Ustaw punkt przerwania w wierszu:
new QC.SqlConnectionStringBuilder(). - Użyj funkcji Edytuj i Kontynuuj, aby celowo źle przeliterować nazwę serwera, kilka wierszy poniżej.
- Pozwól programowi działać, aż powrócisz do punktu przerwania.
- Występuje błąd 40615.
- Napraw błędną pisownię.
- Pozwól programowi uruchomić się i zakończyć pomyślnie.
- Usuń 40615 i ponownie skompiluj.