什么是好的C#编码风格追赶的SQLException并重试 [英] What is good C# coding style for catching SQLException and retrying

查看:110
本文介绍了什么是好的C#编码风格追赶的SQLException并重试的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个调用一个SQLServer函数来执行对表的自由文本搜索的方法。这个函数会偶尔在第一次调用导致SQLException:断字超时为全文查询字符串。所以通常我要重试请求,因为它会在后续请求成功。什么是好的风格以构建重试逻辑。目前,我有以下几点:

  VAR RetryCount重= 0;
VAR的结果=新的List< UserSummaryDto>();
使用(VAR CTX =新UsersDataContext(ConfigurationManager.ConnectionStrings [CONNECTION_STRING_KEY] .ConnectionString))
{
    对于(;)
    {
        尝试
        {
            结果= ctx.SearchPhoneList(值,maxRows进行)
                         。选择(用户= GT; user.ToDto())
                         .ToList();
            打破;
        }
        赶上(SQLEXCEPTION)
        {
            RetryCount重++;
            如果(RetryCount重> MAX_RETRY)抛出;
        }
    }
}返回结果;


解决方案

感谢所有的反馈。我这个回答自己,所以我可以将来自给出的答案元素。请让我知道如果我错过了一些东西。我的方法就变成了:

  VAR的结果=新的List< UserSummaryDto>();
重试< UsersDataContext>(CTX =>业绩= ctx.SearchPhoneList(值,maxRows进行)
                                            。选择(用户= GT; user.ToDto())
                                            .ToList());
返回结果;

和我重构重用原来的方法。仍然很多嵌套层次。它也依赖于学生要这可能是过于严格的数据上下文默认构造函数。 @马丁,我考虑包括您的 preserveStackTrace 的方法,但在这种情况下,我不认为它确实增加了足够的价值 - 好知道以供将来参考感谢:

 私人const int的MAX_RETRY = 2;
私人常量双LONG_WAIT_SECONDS = 5;
私人常量双SHORT_WAIT_SECONDS = 0.5;
私人静态只读时间跨度longWait = TimeSpan.FromSeconds(LONG_WAIT_SECONDS);
私人静态只读时间跨度shortWait = TimeSpan.FromSeconds(SHORT_WAIT_SECONDS);
私人枚举RetryableSqlErrors
{
    超时= -2,
    NOLOCK = 1204,
    死锁= 1205,
    WordbreakerTimeout = 30053,
}私人无效重试< T>(动作< T> retryAction)其中T:DataContext的,新的()
{
    变种RetryCount重= 0;
    使用(VAR CTX =新T())
    {
        为(;;)
        {
            尝试
            {
                retryAction(CTX);
                打破;
            }
            赶上(SQLEXCEPTION EX)
            {
                如果(!Enum.IsDefined(typeof运算(RetryableSqlErrors),ex.Number))
                    扔;                RetryCount重++;
                如果(RetryCount重> MAX_RETRY)抛出;                Thread.sleep代码(ex.Number ==(INT)RetryableSqlErrors.Timeout?
                                                        longWait:shortWait);
            }
        }
    }
}

I have a method that calls a SQLServer function to perform a free text search against a table. That function will occasionally on the first call result in a SQLException: "Word breaking timed out for the full-text query string". So typically I want to retry that request because it will succeed on subsequent requests. What is good style for structuring the retry logic. At the moment I have the following:

var retryCount = 0;
var results = new List<UserSummaryDto>();
using (var ctx = new UsersDataContext(ConfigurationManager.ConnectionStrings[CONNECTION_STRING_KEY].ConnectionString))
{
    for (; ; )
    {
        try
        {
            results = ctx.SearchPhoneList(value, maxRows)
                         .Select(user => user.ToDto())
                         .ToList();
            break;
        }
        catch (SqlException)
        {
            retryCount++;
            if (retryCount > MAX_RETRY) throw;
        }
    }
}

return results;

解决方案

Thanks for all the feedback. I'm answering this myself so I can incorporate elements from the answers given. Please let me know if I've missed something. My method becomes:

var results = new List<UserSummaryDto>();
Retry<UsersDataContext>(ctx => results = ctx.SearchPhoneList(value, maxRows)
                                            .Select(user => user.ToDto())
                                            .ToList());
return results;

And I've refactored the original method for reuse. Still lots of levels of nesting. It also relies on there being a default constructor for the data context which may be too restrictive. @Martin, I considered including your PreserveStackTrace method but in this case I don't think it really adds enough value - good to know for future reference thanks:

private const int MAX_RETRY = 2;
private const double LONG_WAIT_SECONDS = 5;
private const double SHORT_WAIT_SECONDS = 0.5;
private static readonly TimeSpan longWait = TimeSpan.FromSeconds(LONG_WAIT_SECONDS);
private static readonly TimeSpan shortWait = TimeSpan.FromSeconds(SHORT_WAIT_SECONDS);
private enum RetryableSqlErrors
{
    Timeout = -2,
    NoLock = 1204,
    Deadlock = 1205,
    WordbreakerTimeout = 30053,
}

private void Retry<T>(Action<T> retryAction) where T : DataContext, new()
{
    var retryCount = 0;
    using (var ctx = new T())
    {
        for (;;)
        {
            try
            {
                retryAction(ctx);
                break;
            }
            catch (SqlException ex)
            {
                if (!Enum.IsDefined(typeof( RetryableSqlErrors), ex.Number))
                    throw;

                retryCount++;
                if (retryCount > MAX_RETRY) throw;

                Thread.Sleep(ex.Number == (int) RetryableSqlErrors.Timeout ?
                                                        longWait : shortWait);
            }
        }
    }
}

这篇关于什么是好的C#编码风格追赶的SQLException并重试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆