我使用 Microsoft.Practice.TransientFaultHandling 块进行重试逻辑。 现在,我将应用程序切换到 .Net 4.8,并在 SqlConnection 的重试逻辑中使用新的构建。 我想知道我的 SqlCommand 是否需要特殊的重试逻辑(我之前使用过 Polly),或者这是否也是内置的。依赖内置函数时不可能记录重试,这使得测试变得非常困难。
微软在这里声明:
“有一个微妙之处。如果在查询时发生暂时性错误 正在执行时,您的 SqlConnection 对象不会重试连接 手术。它当然不会重试您的查询。 然而, SqlConnection 在发送您的数据之前非常快速地检查连接 查询执行。如果快速检查检测到连接问题, SqlConnection 重试连接操作。如果重试成功, 您的查询已发送以供执行。”
我通过在重试时间范围内断开并重新连接互联网来测试这一点,我的命令在一段时间后被执行。 所以它似乎适用于这个简单的场景。但是依赖于此真的安全吗?还是我仍然需要为我的 SqlCommand 实现重试逻辑?
这是我的代码:
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(ConnectionString);
builder.ConnectRetryCount = 5;
builder.ConnectRetryInterval = 3;
MyDataSet m_myDataSet = new MyDataSet();
using (SqlConnection sqlConnection = new SqlConnection(builder.ConnectionString))
{
try
{
sqlConnection.Open();
}
catch (SqlException sqlEx)
{
// do some logging
return false;
}
try
{
using (SqlCommand cmd = new SqlCommand(selectCmd, sqlConnection))
{
using (SqlDataAdapter da = new SqlDataAdapter(cmd))
{
da.Fill(m_myDataSet, tableName);
}
}
}
}
您问题的答案是分析为什么您与数据库的连接打开时间太长,以至于空闲并超时。 ConnectRetryCount 和 ConnectRetryInterval 属性允许您在服务器识别出空闲连接失败后调整重新连接尝试。我会遵循 Microsoft 对此的建议:
我们强烈建议您在使用时始终关闭连接 使用完毕后,连接将返回到 水池。您可以使用 Close 或 Dispose 方法来完成此操作 连接对象,或者通过使用打开内部的所有连接 C# 中的语句或 Visual Basic 中的Using 语句。连接 没有明确关闭的可能不会被添加或返回到 水池。有关详细信息,请参阅使用声明或如何:处置 Visual Basic 的系统资源。
打开您的连接并在不再需要时关闭它们,如下所示:
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(ConnectionString);
builder.ConnectRetryCount = 5;
builder.ConnectRetryInterval = 3;
bool updateSuccess = true;
MyDataSet m_myDataSet = new MyDataSet();
using (SqlConnection sqlConnection = new SqlConnection(builder.ConnectionString))
{
try
{
sqlConnection.Open();
using (SqlCommand cmd = new SqlCommand(selectCmd, sqlConnection))
{
using (SqlDataAdapter da = new SqlDataAdapter(cmd))
{
da.Fill(m_myDataSet, tableName);
}
}
}
catch (SqlException sqlEx)
{
// do some logging (avoid exceptions here)
updateSuccess = false;
}
finally
{
sqlConnection.Close();
}
}
return updateSuccess;
希望有帮助。
快乐编码!!!
不,这并不真正安全,但这取决于您的要求。假设您正在使用内置的
ConnectRetryCount
。正如您引用的 MS 报价中所示,它有很小的可能不会重试该操作并且会失败。如果您的应用程序是基于 UI 的,您可能会认为这个小风险是可以接受的,并要求用户重试。但是,如果您的应用程序正在运行可靠性很重要的关键后台服务,则您应该实现自己的重试逻辑。您可以执行此操作来代替内置重试逻辑,也可以同时执行这两种操作。我建议前者避免因同时运行两种不同的重试机制而产生意外影响的可能性。
在使用 Azure 实现自定义重试逻辑时,您引用的 MS 文章建议在第一次重试之前等待 5 秒,以避免云服务不堪重负。它还建议增加每次后续重试的延迟。下面是同时实现这两种功能的实现。
假设这是您与 Azure DB 的连接代码:
using (var myDataSource = new SqlDataAdapter(query, connectionString))
{
myDataSource.Fill(destinationDataTable);
}
这里是使用简单同步实现的具有自定义重试逻辑的相同代码。这会重试查询最多 5 次,从 5 秒等待开始,并在后续重试之间每次将等待时间加倍:
bool querySuccess = false;
int numAttemptsMade = 0;
int retryInterval = 5000; // in milliseconds
const int maxNumAttempts = 5;
do
{
if (numAttemptsMade > 0)
{
Thread.Sleep(retryInterval);
retryInterval *= 2; // retry after 5 seconds, then 10, then 20, etc.
}
numAttemptsMade++;
Console.Write($"Connecting to Azure DB. Attempt {numAttemptsMade} of {maxNumAttempts}...");
try
{
using (var myDataSource = new SqlDataAdapter(query, connectionString))
{
myDataSource.Fill(destinationDataTable);
querySuccess = true;
}
}
catch (Exception ex)
{
Console.Write($"Error retrieving data: {ex.Message}");
}
}
while (!querySuccess && numAttemptsMade < maxNumAttempts);