处理数据库连接问题的正确方法

时间:2018-03-30 07:32:54

标签: c# ado.net azure-sql-database sqlconnection

我在尝试连接数据库时遇到以下错误:

  

发生与网络相关或特定于实例的错误   建立与SQL Server的连接。找不到服务器或   无法访问。验证实例名称是否正确   SQL Server配置为允许远程连接。 (提供者:命名   管道提供程序,错误:40 - 无法打开与SQL Server的连接)

现在有时我得到这个错误,有时我不这样做,例如:当我第一次运行我的程序时,它成功打开连接,当我第二次运行时,我得到这个错误,下次我运行我的程序然后我不会得到错误。

当我尝试通过SSMS连接到同一个数据库服务器时,我能够成功连接,但我只在我的程序中遇到此网络问题。

数据库不在我的 LOCAL .Its AZURE

我的本​​地数据库没有出现此错误。

代码:

public class AddOperation
{
    public void Start()
    {
          using (var processor = new MyProcessor())
          {
              for (int i = 0; i < 2; i++)
              {
                  if(i==0)
                  {
                     var connection = new SqlConnection("Connection string 1");
                     processor.Process(connection);
                  }
                  else
                  {
                      var connection = new SqlConnection("Connection string 2");
                      processor.Process(connection);
                  }   
              }
          }
    }       
}

public class MyProcessor : IDisposable
{
    public void Process(DbConnection cn)
        {
            using (var cmd = cn.CreateCommand())
            {
                cmd.CommandText = "query";
                cmd.CommandTimeout = 1800;
                cn.Open();//Sometimes work sometimes dont
                using (var reader = cmd.ExecuteReader(CommandBehavior.CloseConnection))
                { 
                   //code
                }
            }
        }
}

所以我对两件事感到困惑:

1) ConnectionTimeout:我是否应该增加connectiontimeout并解决我的异常连接问题?

2)重试尝试策略:我应该实现如下的重试连接机制:

public static void OpenConnection(DbConnection cn, int maxAttempts = 1)
        {
            int attempts = 0;
            while (true)
            {
                try
                {
                    cn.Open();
                    return;
                }
                catch
                {
                    attempts++;
                    if (attempts >= maxAttempts) throw;
                }
            }
        }

我对上面两个选项感到困惑。

任何人都可以建议我处理这个问题的更好方法是什么?

7 个答案:

答案 0 :(得分:5)

正如您可以阅读here,即使安装在Azure VM(IaaS)上的SQL Server,也建议使用重试逻辑。

  

故障处理:您的应用程序代码包括重试逻辑和   瞬态故障处理?包括适当的重试逻辑和瞬态   代码中的故障处理修复应该是通用的最佳方法   在本地和云中实践,无论是IaaS还是PaaS。如果   缺少这种特性,两者都可能出现应用问题   Azure VM中的Azure SQLDB和SQL Server,但在此方案中   后者被推荐超过前者。

建议使用增量重试逻辑。

从应用程序需要的应用程序块中实例化对象有两种基本方法。在第一种方法中,您可以显式实例化代码中的所有对象,如以下代码段所示:

var retryStrategy = new Incremental(5, TimeSpan.FromSeconds(1), 
  TimeSpan.FromSeconds(2));

var retryPolicy =
  new RetryPolicy<SqlDatabaseTransientErrorDetectionStrategy>(retryStrategy);

在第二种方法中,您可以从配置数据中实例化和配置对象,如以下代码段所示:

// Load policies from the configuration file.
// SystemConfigurationSource is defined in 
// Microsoft.Practices.EnterpriseLibrary.Common.
using (var config = new SystemConfigurationSource())
{
  var settings = RetryPolicyConfigurationSettings.GetRetryPolicySettings(config);

  // Initialize the RetryPolicyFactory with a RetryManager built from the 
  // settings in the configuration file.
  RetryPolicyFactory.SetRetryManager(settings.BuildRetryManager());

  var retryPolicy = RetryPolicyFactory.GetRetryPolicy
  <SqlDatabaseTransientErrorDetectionStrategy>("Incremental Retry Strategy");   
   ... 
   // Use the policy to handle the retries of an operation.

}

有关详细信息,请访问this文档。

答案 1 :(得分:3)

使用新版本的.NET(4.6.1或更高版本),然后利用内置的弹性功能:

ConnectRetryCount,ConnectRetryInterval和Connection Timeout。

有关详细信息,请参阅:https://docs.microsoft.com/en-us/azure/sql-database/sql-database-connectivity-issues#net-sqlconnection-parameters-for-connection-retry

答案 2 :(得分:2)

与远程服务通信的所有应用程序都对瞬态故障敏感。

如其他答案中所述,如果您的客户端程序使用.NET Framework类System.Data.SqlClient.SqlConnection连接到SQL数据库,请使用.NET 4.6.1或更高版本(或.NET Core)以便您可以使用其连接重试功能。

为SqlConnection对象构建连接字符串时,请协调以下参数之间的值:

ConnectRetryCount :默认值为1.范围是0到255。

ConnectRetryInterval :默认值为1秒。范围是1到60。

连接超时:默认为15秒。范围是0到2147483647。

具体而言,您选择的值应使以下等式为真:

Connection Timeout = ConnectRetryCount * ConnectionRetryInterval

现在,来到选项2,当您的应用程序具有自定义重试逻辑时,它将增加总重试次数 - 对于每次自定义重试,它将尝试ConnectRetryCount次。例如如果ConnectRetryCount = 3并且自定义重试= 5,它将尝试15次尝试。您可能不需要那么多次重试。

如果您只考虑自定义重试与连接超时:

连接超时通常是由于网络损耗 - 网络丢失率较高(例如,蜂窝或弱WiFi)或高流量负载。您可以选择在其中使用的最佳策略。

以下指南有助于解决瞬态错误:

  1. https://docs.microsoft.com/en-us/azure/sql-database/sql-database-connectivity-issues

  2. https://docs.microsoft.com/en-in/azure/architecture/best-practices/transient-faults

答案 3 :(得分:1)

您使用的是SQL Express还是Workgroup Edition?如果是这样,服务器可能太忙而无法响应。

要排除网络问题,请在命令提示符下执行PING -t SqlServername。每次ping都会回来,还是有些丢失?这可能是网络中断的指示,也可能导致此错误,如错误的交换机。如果它们所有丢失,那么(假设您的数据库连接有时可行),很可能某个地方的防火墙阻止了ping:如果找到该块并暂时取消阻止,它可能有助于诊断。 / p>

错误消息表明您正在使用命名管道。你是故意使用命名管道吗?对于大多数方案(包括Azure数据库),我建议在SQL Server配置管理器中启用TCP / IP并禁用命名管道。

取决于远方&#39;您的Azure数据库是因为路由器和防火墙有时会破坏Kerberos和/或相关时间的延迟。您可以通过使用连接字符串中的端口来避免这种情况,以避免到端口1434的往返来枚举实例。我假设您已经在使用FQDN。例如:server \ instance,port

答案 4 :(得分:1)

连接完全可能掉线。 &#34;分布式计算的谬误&#34; :)。 这可能是网络连接问题。可以在任何一端。

我建议:(假设您的计算机在Azure上启用了防火墙)

  1. Ping服务器并查看是否有任何丢失。
  2. ping(服务器).database.windows.net

    1. tracert
    2. telnet也可以是你的朋友。
    3. 以上三项应该可以帮助您确定问题所在。

      我认为您的重试逻辑很好。

      关于你的问题

      增加超时 只有当您确定您的查询需要很长时间时。如果对于简单插入,您必须增加超时问题,可能是网络连接。

      重试逻辑 如上所述,它现在是您可以使用的框架的一部分,或者您创建的框架应该没问题。理想情况下,即使您确定连接和速度,重试逻辑也很不错。以防万一:)

答案 5 :(得分:1)

您应该增加超时,因为建立与SQL Server的连接所需的时间有很多步骤,因此第一次建立连接需要一些时间。建立连接后,将连接汇集在内存中,以便在后续查询中重复使用。

有关连接池的更多详细信息,请参阅以下链接: https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql-server-connection-pooling

正如您所提到的那样,有时会产生此错误,并非总是如此,因此可能存在一些网络和连接因素。 SQL连接的默认超时为15秒。我想如果你把它改成30秒,它应该可以工作。

答案 6 :(得分:1)

考虑使用Polly

您可以使用一段简单的代码,例如 -

RetryPolicy retryPolicy = Policy.Handle<Exception>()
            .WaitAndRetry(3, retryAttempt => 
TimeSpan.FromSeconds(retryAttempt));

var result = retryPolicy.Execute(() => someClass.DoSomething());

这将最多重试该请求三次。