Sdílet prostřednictvím


SqlCommand.RetryLogicProvider Vlastnost

Definice

Získá nebo nastaví hodnotu, která určuje SqlRetryLogicBaseProvider objekt vázaný na tento příkaz.

public:
 property Microsoft::Data::SqlClient::SqlRetryLogicBaseProvider ^ RetryLogicProvider { Microsoft::Data::SqlClient::SqlRetryLogicBaseProvider ^ get(); void set(Microsoft::Data::SqlClient::SqlRetryLogicBaseProvider ^ value); };
[System.ComponentModel.Browsable(false)]
public Microsoft.Data.SqlClient.SqlRetryLogicBaseProvider RetryLogicProvider { get; set; }
public Microsoft.Data.SqlClient.SqlRetryLogicBaseProvider RetryLogicProvider { get; set; }
[<System.ComponentModel.Browsable(false)>]
member this.RetryLogicProvider : Microsoft.Data.SqlClient.SqlRetryLogicBaseProvider with get, set
member this.RetryLogicProvider : Microsoft.Data.SqlClient.SqlRetryLogicBaseProvider with get, set
Public Property RetryLogicProvider As SqlRetryLogicBaseProvider

Hodnota vlastnosti

Pokud je nastavená hodnota null (výchozí), použije se výchozí zprostředkovatel, který se nedá opakovat.

Atributy

Poznámky

Před provedením příkazu je nutné nastavit hodnotu této vlastnosti, aby se projevila.

Pokud chcete použít logiku opakování, proveďte před spuštěním příkazu následující kroky:

  1. Definujte parametry konfigurace pomocí SqlRetryLogicOption typu .
  2. SqlRetryLogicBaseProvider Vytvořte objekt pomocí jedné z následujících statických SqlConfigurableRetryFactory metod třídy :
  3. Přiřaďte SqlRetryLogicBaseProvider objekt vlastnosti RetryLogicProvider .

Poznámka

Detekce opakovaných výjimek je důležitou součástí vzorce opakování. Před použitím logiky opakování je důležité prozkoumat výjimky a zvolit poskytovatele opakování, který nejlépe odpovídá vašemu scénáři. Nejprve protokolujte výjimky a vyhledejte přechodné chyby.

Poznámka

Časový limit příkazu se restartuje při každém spuštění příkazu v rámci logiky opakování a po použití zpoždění opakování. Mezi těmito dvěma akcemi nedochází k žádnému překrývání časů.

Poznámka

Výchozí zprostředkovatel logiky opakování není povolený, pokud není nakonfigurovaný v konfiguračním souboru aplikace. Další informace najdete v tématu Konfigurovatelný konfigurační soubor logiky opakování.

Upozornění

Příkaz s CommandBehavior.CloseConnection není kompatibilní s integrovanou logikou opakování. Základní připojení se okamžitě ukončí po prvním pokusu o spuštění a už není k dispozici pro další opakování.

Příklad

Následující ukázka vytvoří databázi a naváže k ní aktivní připojení. Zatímco databáze má aktivní připojení, pokusí se ho zrušit pomocí nového SqlConnection a objektu , SqlCommand který používá SqlRetryLogicBaseProvider. Před překročením počtu opakování byste měli ukončovat aktivní připojení prostřednictvím databáze, abyste odblokovali druhý příkaz.
Blokující připojení simuluje situaci, jako je příkaz, který stále běží v databázi a pravděpodobně se nedokončí.

/// Detecting retriable exceptions is a vital part of the retry pattern.
/// Before applying retry logic it is important to investigate exceptions and choose a retry provider that best fits your scenario.
/// First, log your exceptions and find transient faults.
/// The purpose of this sample is to illustrate how to use this feature and the condition might not be realistic.

    private const string DefaultDB = "Northwind";
    private const string CnnStringFormat = "Server=localhost; Initial Catalog={0}; Integrated Security=true; pooling=false;";
    private const string DropDatabaseFormat = "DROP DATABASE {0}";
    private const string CreateDatabaseFormat = "CREATE DATABASE {0}";

    // For general use
    private static SqlConnection s_generalConnection = new SqlConnection(string.Format(CnnStringFormat, DefaultDB));

    static void Main(string[] args)
    {
        // 1. Define the retry logic parameters
        var options = new SqlRetryLogicOption()
        {
            NumberOfTries = 5,
            MaxTimeInterval = TimeSpan.FromSeconds(20),
            DeltaTime = TimeSpan.FromSeconds(1),
            AuthorizedSqlCondition = null,
            // error number 3702 : Cannot drop database "xxx" because it is currently in use.
            TransientErrors = new int[] {3702}
        };

        // 2. Create a retry provider
        var provider = SqlConfigurableRetryFactory.CreateExponentialRetryProvider(options);

        // define the retrying event to report execution attempts
        provider.Retrying += (object s, SqlRetryingEventArgs e) =>
            {
                int attempts = e.RetryCount + 1;
                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.WriteLine($"attempt {attempts} - current delay time:{e.Delay} \n");
                Console.ForegroundColor = ConsoleColor.DarkGray;
                if (e.Exceptions[e.Exceptions.Count - 1] is SqlException ex)
                {
                    Console.WriteLine($"{ex.Number}-{ex.Message}\n");
                }
                else
                {
                    Console.WriteLine($"{e.Exceptions[e.Exceptions.Count - 1].Message}\n");
                }

                // It is not good practice to do time-consuming tasks inside the retrying event which blocks the running task.
                // Use parallel programming patterns to mitigate it.
                if (e.RetryCount == provider.RetryLogic.NumberOfTries - 1)
                {
                    Console.WriteLine("This is the last chance to execute the command before throwing the exception.");
                    Console.WriteLine("Press Enter when you're ready:");
                    Console.ReadLine();
                    Console.WriteLine("continue ...");
                }
            };

        // Open a general connection.
        s_generalConnection.Open();

        try
        {
            // Assume the database is creating and other services are going to connect to it.
            RetryCommand(provider);
        }
        catch
        {
            s_generalConnection.Close();
            // exception is thrown if connecting to the database isn't successful.
            throw;
        }
        s_generalConnection.Close();
    }

    private static void ExecuteCommand(SqlConnection cn, string command)
    {
        using var cmd = cn.CreateCommand();
        cmd.CommandText = command;
        cmd.ExecuteNonQuery();
    }

    private static void FindActiveSessions(SqlConnection cnn, string dbName)
    {
        using var cmd = cnn.CreateCommand();
        cmd.CommandText = "DECLARE @query NVARCHAR(max) = '';" + Environment.NewLine +
            $"SELECT @query = @query + 'KILL ' + CAST(spid as varchar(50)) + ';' FROM sys.sysprocesses WHERE dbid = DB_ID('{dbName}')" + Environment.NewLine +
            "SELECT @query AS Active_sessions;";
        var reader = cmd.ExecuteReader();
        if (reader.Read())
        {
            Console.ForegroundColor = ConsoleColor.Green;
            Console.Write($">> Execute the '{reader.GetString(0)}' command in SQL Server to unblock the running task.");
            Console.ResetColor();
        }
        reader.Close();
    }

Jak používat synchronní příkazy

private static void RetryCommand(SqlRetryLogicBaseProvider provider)
{
    // Change this if you already have a database with the same name in your database.
    string dbName = "RetryCommand_TestDatabase";

    // Subscribe a new event on retry event and discover the active sessions on a database
    EventHandler<SqlRetryingEventArgs> retryEvent = (object s, SqlRetryingEventArgs e) =>
    {
        // Run just at first execution
        if (e.RetryCount == 1)
        {
            FindActiveSessions(s_generalConnection, dbName);
            Console.WriteLine($"Before exceeding {provider.RetryLogic.NumberOfTries} attempts.");
        }
    };

    provider.Retrying += retryEvent;

    // Create a new database.
    ExecuteCommand(s_generalConnection, string.Format(CreateDatabaseFormat, dbName));
    Console.WriteLine($"The '{dbName}' database is created.");

    // Open a connection to the newly created database to block it from being dropped.
    using var blockingCnn = new SqlConnection(string.Format(CnnStringFormat, dbName));
    blockingCnn.Open();
    Console.WriteLine($"Established a connection to '{dbName}' to block it from being dropped.");

    Console.WriteLine($"Dropping `{dbName}`...");
    // Try to drop the new database.
    RetryCommandSync(provider, dbName);

    Console.WriteLine("Command executed successfully.");

    provider.Retrying -= retryEvent;
}

private static void RetryCommandSync(SqlRetryLogicBaseProvider provider, string dbName)
{
    using var cmd = s_generalConnection.CreateCommand();
    cmd.CommandText = string.Format(DropDatabaseFormat, dbName);
    // 3. Assign the `provider` to the command
    cmd.RetryLogicProvider = provider;
    Console.WriteLine("The first attempt, before getting into the retry logic.");
    cmd.ExecuteNonQuery();
}

Použití s asynchronními příkazy

private static void RetryCommand(SqlRetryLogicBaseProvider provider)
{
    // Change this if you already have a database with the same name in your database.
    string dbName = "RetryCommand_TestDatabase";

    // Subscribe to the retry event and discover active sessions in a database
    EventHandler<SqlRetryingEventArgs> retryEvent = (object s, SqlRetryingEventArgs e) =>
    {
        // Run just at first execution
        if (e.RetryCount == 1)
        {
            FindActiveSessions(s_generalConnection, dbName);
            Console.WriteLine($"Before exceeding {provider.RetryLogic.NumberOfTries} attempts.");
        }
    };

    provider.Retrying += retryEvent;

    // Create a new database.
    ExecuteCommand(s_generalConnection, string.Format(CreateDatabaseFormat, dbName));
    Console.WriteLine($"The '{dbName}' database is created.");

    // Open a connection to the newly created database to block it from being dropped.
    using var blockingCnn = new SqlConnection(string.Format(CnnStringFormat, dbName));
    blockingCnn.Open();
    Console.WriteLine($"Established a connection to '{dbName}' to block it from being dropped.");

    Console.WriteLine("Dropping the database...");
    // Try to drop the new database.
    RetryCommandAsync(provider, dbName).Wait();

    Console.WriteLine("Command executed successfully.");

    provider.Retrying -= retryEvent;
}

private static async Task RetryCommandAsync(SqlRetryLogicBaseProvider provider, string dbName)
{
    using var cmd = s_generalConnection.CreateCommand();
    cmd.CommandText = string.Format(DropDatabaseFormat, dbName);
    // 3. Assign the `provider` to the command
    cmd.RetryLogicProvider = provider;
    Console.WriteLine("The first attempt, before getting into the retry logic.");
    await cmd.ExecuteNonQueryAsync();
}

Použití se staršími asynchronními příkazy

Kromě přiřazení zprostředkovatele k příkazu a spuštění příkazu je možné ho spustit přímo pomocí následujících SqlRetryLogicBaseProvider metod:

private static void RetryCommand(SqlRetryLogicBaseProvider provider)
{
    // Change this if you already have a database with the same name in your database.
    string dbName = "RetryCommand_TestDatabase";

    // Subscribe to the retry event and discover the active sessions in a database
    EventHandler<SqlRetryingEventArgs> retryEvent = (object s, SqlRetryingEventArgs e) =>
    {
        // Run just at first execution
        if (e.RetryCount == 1)
        {
            FindActiveSessions(s_generalConnection, dbName);
            Console.WriteLine($"Before exceeding {provider.RetryLogic.NumberOfTries} attempts.");
        }
    };

    provider.Retrying += retryEvent;

    // Create a new database.
    ExecuteCommand(s_generalConnection, string.Format(CreateDatabaseFormat, dbName));
    Console.WriteLine($"The '{dbName}' database is created.");

    // Open a connection to the newly created database to block it from being dropped.
    using var blockingCnn = new SqlConnection(string.Format(CnnStringFormat, dbName));
    blockingCnn.Open();
    Console.WriteLine($"Established a connection to '{dbName}' to block it from being dropped.");

    Console.WriteLine("Dropping the database...");
    // Try to drop the new database.
    RetryCommandBeginExecuteAsync(provider, dbName).Wait();

    Console.WriteLine("Command executed successfully.");

    provider.Retrying -= retryEvent;
}

private static async Task RetryCommandBeginExecuteAsync(SqlRetryLogicBaseProvider provider, string dbName)
{
    using var cmd = s_generalConnection.CreateCommand();
    cmd.CommandText = string.Format(DropDatabaseFormat, dbName);
    // Execute the BeginExecuteXXX and EndExecuteXXX functions by using Task.Factory.FromAsync().
    // Apply the retry logic by using the ExecuteAsync function of the configurable retry logic provider.
    Console.WriteLine("The first attempt, before getting into the retry logic.");
    await provider.ExecuteAsync(cmd, () => Task.Factory.FromAsync(cmd.BeginExecuteNonQuery(), cmd.EndExecuteNonQuery));
}

Poznámka

Asynchronní programovací model (APM) je starší model, který používá dvojici metod začínajících Begin na a Enda rozhraní s názvem IAsyncResult. Nedoporučujeme používat tento vzor v nových aplikacích. Tyto metody jsou určené pro zpětnou kompatibilitu.

Platí pro