Notatka
Dostęp do tej strony wymaga autoryzacji. Może 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ł przedstawia przykładowy kod w C#, który demonstruje ręcznie implementowaną logikę powtórek. Logika powtórek obsługuje tymczasowe błędy lub przejściowe błędy, które mogą zostać usunięte, jeśli program poczeka i spróbuje operacji ponownie.
Important
W przypadku nowych aplikacji korzystających z Microsoft.Data.SqlClient 3.0 lub nowszego należy używać konfigurowalnego mechanizmu ponawiania prób sterownika zamiast implementować pętlę ponawiania prób. Zacznij od konfigurowania logiki ponawiania w SqlClient.
Źródła błędów przejściowych obejmują:
- Krótka awaria sieci obsługującej Internet.
- System chmurowy może równoważyć obciążenie zasobów, gdy przychodzi twoje zapytanie.
Klasy ADO.NET do łączenia z SQL Server mogą również łączyć się z Azure SQL Database. Twój program klienta może napotkać przejściowe usterki. Powinno dojść do odzyskania sprawności przez zastosowanie ograniczonej zasady ponawiania prób odpowiedniej dla danej operacji.
Krok 1. Identyfikowanie błędów przejściowych
Twój program musi rozróżniać błędy przejściowe od błędów trwałych. Błędy przejściowe to stany błędu, które mogą szybko ustąpić, takie jak przejściowe problemy sieciowe. Przykładem trwałego błędu jest błędna pisownia nazwy docelowej bazy danych. W takim przypadku błąd "Nie znaleziono takiej bazy danych" pozostaje i nie znika szybko.
Lista numerów błędów sklasyfikowanych jako usterki przejściowe jest dostępna w sekcji Komunikaty o błędach dla aplikacji klientów baz danych SQL.
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 w 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#.
Wybierz Plik>Nowy>Projekt>Zainstalowane>Szablony>Visual C#>Windows>Klasyczny pulpit>Aplikacja konsolowa.
Nadaj projektowi
RetryAdo2nazwę .
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.Zastąp całą zawartość
Program.cspliku kodem z następującego bloku kodu.Wybierz menu Buduj>Buduj Rozwiązanie.
Krok 2.b. Kopiowanie i wklejanie przykładowego kodu
Wklej ten kod do swojego Program.cs pliku.
Następnie edytuję ciągi znaków dla nazwy serwera i hasła. Te ciągi można znaleźć w metodzie o nazwie GetSqlConnectionString.
Notatka
Parametr połączenia jest przeznaczony dla usługi Azure SQL Database, ponieważ zawiera czteroznakowy prefiks tcp:. Ale możesz dostosować string serwera, aby połączyć się z instancją 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
Plik RetryAdo2.exe wykonywalny nie przyjmuje parametrów. Aby uruchomić .exe:
- Otwórz okno konsoli w folderze, w którym skompilowałeś plik binarny
RetryAdo2.exe. - Uruchom
RetryAdo2.exebez 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
Możesz symulować błąd przejściowy, aby przetestować logikę powtórek na kilka sposobów.
Krok 3.a. Zgłaszanie wyjątku testowego
Przykładowy kod zawiera następujące elementy:
- Mała klasa pochodna
TestSqlExceptionz właściwością o nazwieNumber. -
//throw new TestSqlException(4060);, który można odkomentować.
Jeśli odkomentujesz instrukcję throw i ponownie skompilujesz program, przy następnym uruchomieniu element RetryAdo2.exe wyświetli coś podobnego 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 radzi sobie z błędami trwałymi, ponownie przeprowadź poprzedni test. Zamiast używać rzeczywistego numeru błędu przejściowego, jak 4060, użyj fikcyjnego numeru 7654321. Program traktuje tę liczbę jako stały błąd i omija wszelkie próby ponowne.
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ą.
- Zacznij
RetryAdo2.exe, i poczekaj, aż konsola wyświetli pierwszy błąd przejściowy, prawdopodobnie 11001. - Ponownie połącz się z siecią, podczas gdy
RetryAdo2.exenadal działa. - Obserwuj raport konsoli, który potwierdzi sukces przy kolejnym ponowieniu.
Krok 3.d: Tymczasowo błędnie zapisz nazwę serwera
- Tymczasowo dodaj 40615 jako kolejny numer błędu do
TransientErrorNumbers, i skompiluj ponownie. - 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.