簡體   English   中英

如果超時失敗,C#重試Sql查詢

[英]C# Retry Sql Query if Timeout Failed

當我的查詢超時並導致失敗。 重試執行查詢的最佳方法是什么?

我在執行查詢之前驗證連接是否已打開。 但是,由於任何給定時間的服務器負載,可能需要<1分鍾到5分鍾以上。 我想擴展CommandTimeout,但我不相信這是真正的方法。

這是我的SQL查詢代碼。 感謝您的所有幫助。

    private static void ExecuteQuery(string connectionString, string query)
    {
        SqlConnection connection = new SqlConnection(connectionString);
        DataTable output = new DataTable();

        try
        {
            //create new SqlAdataAdapter
            SqlDataAdapter command = new SqlDataAdapter {SelectCommand = new SqlCommand(query, connection)};

            //connect to Sqldb
            connection.Open();

            //validate connection to database before executing query
            if (connection.State != ConnectionState.Open) return;
            Console.WriteLine("Connection successful\nExecuting query...");

            //set connection timeout
            command.SelectCommand.CommandTimeout = 200;

            //create new dataSet in order to input output of query to
            DataSet dataSet = new DataSet();

            //fill the dataSet
            command.Fill(dataSet, "capacity");
            DataTable dtTable1 = dataSet.Tables["capacity"];

            Console.WriteLine("There are " + dtTable1.Rows.Count + " clusters within the capacity anlaysis.");

            output = dtTable1;
        }
        catch (Exception e)
        {
            Console.WriteLine("Unable to execute capacity (all records) query due to {0}", e.Message);
        }
        finally
        {
            connection.Close();

            Declarations.NumOfClusters = output.Rows.Count;
            Declarations.finalIssues = Issues(output, 2m, 20, true);

            Console.WriteLine("\n---------------Successfully Created Capacity DataSet---------------\n");
        }
    }

使用Palmer庫: https//github.com/mitchdenny/palmer

  Retry.On<Exception>().For(TimeSpan.FromSeconds(15)).With(context =>
  {
    // Code that might periodically fail due to some issues.
       ExecuteQuery(string connectionString, string query)
       if (contect.DidExceptionLastTime)
           Thread.Sleep(200); // what ever you wish
   });

請參閱github頁面上的API。 例如,您可以檢查異常的上下文,並在發生異常時決定休眠一段時間。 您可以在更具體的例外情況下重試。 你可以永遠嘗試,等等。

以某種方式重新構造代碼,以便它允許您遞歸地調用查詢,直到獲得所需的結果。

例如。

private static void ExecuteQuery(string connectionString, string query)
{
    SqlConnection connection = new SqlConnection(connectionString);
    DataTable output = null;

    while output is null
    {
        output = getDataFromDB(query);
    }

    if(output is DataTable && output.Rows.Count > 0)
    {
        Console.WriteLine("There are " + output.Rows.Count + " clusters within the capacity analysis.");
    }
}

private DataTable getDataFromDB(string query)
{
    DataTable oDTResult = null;

    try
    {
        //create new SqlAdataAdapter
        SqlDataAdapter command = new SqlDataAdapter {SelectCommand = new SqlCommand(query, connection)};

        //connect to Sqldb
        connection.Open();

        //validate connection to database before executing query
        if (connection.State != ConnectionState.Open) return;
        Console.WriteLine("Connection successful\nExecuting query...");

        //set connection timeout
        command.SelectCommand.CommandTimeout = 200;

        //create new dataSet in order to input output of query to
        DataSet dataSet = new DataSet();

        //fill the dataSet
        command.Fill(dataSet, "capacity");
        DataTable dtTable1 = dataSet.Tables["capacity"];            

        oDTResult = dtTable1;
    }
    catch (Exception e)
    {
        Console.WriteLine("Unable to execute capacity (all records) query due to {0}", e.Message);
    }
    finally
    {
        connection.Close();

        Declarations.NumOfClusters = output.Rows.Count;
        Declarations.finalIssues = Issues(output, 2m, 20, true);

        Console.WriteLine("\n---------------Successfully Created Capacity DataSet---------------\n");
    }

    return oDTResult;
}

您可能希望配合程序應嘗試執行此操作的重試次數,以賦予其一定的靈活性。

此外,如果您的查詢花了這么長時間,您應該研究如何優化SQL Server數據庫以借助視圖/索引等減少執行時間。

重試操作的通用方法

 public static class Retry
    {
       public static void Do(
           Action action,
           TimeSpan retryInterval,
           int retryCount = 3)
       {
           Do<object>(() => 
           {
               action();
               return null;
           }, retryInterval, retryCount);
       }

       public static T Do<T>(
           Func<T> action, 
           TimeSpan retryInterval,
           int retryCount = 3)
       {
           var exceptions = new List<Exception>();

           for (int retry = 0; retry < retryCount; retry++)
           {
              try
              { 
                  if (retry > 0)
                      Thread.Sleep(retryInterval);
                  return action();
              }
              catch (Exception ex)
              { 
                  exceptions.Add(ex);
              }
           }

           throw new AggregateException(exceptions);
           }
        }

您現在可以使用此實用程序方法執行重試邏輯:

Retry.Do(() => SomeFunctionThatCanFail(), TimeSpan.FromSeconds(1));

我在asp.net web表單中編寫了一個示例代碼,運行了10次。

        static int noOfTries = 0;
        protected void Page_Load(object sender, EventArgs e)
        {
            function();
        }

        private void function()
        {

            try
            {

                if (noOfTries == 10) goto XX;
                noOfTries++;
                int a = 0;
                int b = 1 / a;


            }
            catch (Exception ew)
            {
                Response.Write(ew.Message + "<br/>");
                function();

            }
            XX:
            int c = 0;
        }

注意:使用靜態變量時,它不是線程安全的

static int noOfTries=0多線程執行可能無法正常工作,因為靜態變量將在多線程中共享。

解決使用Session["noOfTries"]

如果是多線程執行環境。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM