복붙노트

[SQL] 좋은 C 번호가되는 SQLException을 잡기 및 재 시도에 대한 코딩 스타일이란

SQL

좋은 C 번호가되는 SQLException을 잡기 및 재 시도에 대한 코딩 스타일이란

나는 테이블에 대해 자유 텍스트 검색을 수행 할 수있는 SQLServer에 함수를 호출하는 방법이있다. 이 함수는 가끔되는 SQLException의 첫 번째 호출 결과에 대한 것입니다 : "단어는 전체 텍스트 쿼리 문자열을 타임 아웃 브레이크와". 그래서 일반적으로 나는 그것이 후속 요청에 성공할 수 있기 때문에 해당 요청을 다시 시도합니다. 구조 재시도 논리에 대한 좋은 스타일은 무엇입니까. 순간 나는 다음 있습니다 :

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;

해결법

  1. ==============================

    1.나는 특정 오류 만 재 시도에 예외 처리를 변경할 것입니다 :

    나는 특정 오류 만 재 시도에 예외 처리를 변경할 것입니다 :

    다음은 기본 "다시 시도"오류입니다

    catch (SqlException ex)
    {
        if !(ex.Number == 1205 || ex.Number == 1204 || ... )
        {
            throw
        }
        retryCount++;
        if (retryCount > MAX_RETRY) throw;
    }
    

    당신은 SQL 상자를 망치하지 않도록 편집, 나는 대기 잊어 청소 :

    편집 2 :

    나는 많은 C #을하지 마십시오 개발자 DBA입니다. 내 대답은 통화에 대한 올바른 예외 처리했다 ...

  2. ==============================

    2.모든 의견을 주셔서 감사합니다. 나는 주어진 답변에서 요소를 통합 할 수 있도록 나는이 나 자신에 대답하고있다. 내가 뭔가를 놓친 적이 있으면 알려 주시기 바랍니다. 내 방법이된다 :

    모든 의견을 주셔서 감사합니다. 나는 주어진 답변에서 요소를 통합 할 수 있도록 나는이 나 자신에 대답하고있다. 내가 뭔가를 놓친 적이 있으면 알려 주시기 바랍니다. 내 방법이된다 :

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

    그리고 재사용을 위해 원래의 방법을 리팩토링했습니다. 중첩 수준의 아직도 많이. 또한이 너무 제한 될 수있는 데이터 컨텍스트에 대한 기본 생성자 인에 의존한다. @Martin, 나는 당신의 PreserveStackTrace 방법을 포함하여 고려하지만,이 경우에 나는 정말 충분히 값 추가 생각하지 않는다 - 향후 참조 덕분에 대해 알고 좋은 :

    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)
                    when (ex.Number == (int) RetryableSqlErrors.Timeout &&
                          retryCount < MAX_RETRY)
                {
                    Thread.Sleep(longWait);
                }
                catch (SqlException ex)
                    when (Enum.IsDefined(typeof(RetryableSqlErrors), ex.Number) &&
                          retryCount < MAX_RETRY)
                {
                    Thread.Sleep(shortWait);
                }
                retryCount++;
            }
        }
    }
    
  3. ==============================

    3.이 같은 SQL 외모에 대한 retryables 내 열거 :

    이 같은 SQL 외모에 대한 retryables 내 열거 :

    SqlConnectionBroken = -1,
    SqlTimeout = -2,
    SqlOutOfMemory = 701,
    SqlOutOfLocks = 1204,
    SqlDeadlockVictim = 1205,
    SqlLockRequestTimeout = 1222,
    SqlTimeoutWaitingForMemoryResource = 8645,
    SqlLowMemoryCondition = 8651,
    SqlWordbreakerTimeout = 30053
    
  4. ==============================

    4.당신은 단순히 기존 코드를 변경하고 처리 할 수 ​​없기 때문에, 그것은 좋은 스타일이 아니다, 그러나 때때로 당신은 그것을해야한다.

    당신은 단순히 기존 코드를 변경하고 처리 할 수 ​​없기 때문에, 그것은 좋은 스타일이 아니다, 그러나 때때로 당신은 그것을해야한다.

    나는이 시나리오에 대한 다음과 같은 일반적인 방법을 사용하고 있습니다. 때때로 다시 던져 시나리오에서 매우 도움이 될 수있는 PreserveStackTrace () 메소드를합니다.

    public static void RetryBeforeThrow<T>(Action action, int retries, int timeout) where T : Exception
    {
        if (action == null)
            throw new ArgumentNullException("action", string.Format("Argument '{0}' cannot be null.", "action"));
    
        int tries = 1;
    
        do
        {
            try
            {
                action();
                return;
            }
            catch (T ex)
            {
                if (retries <= 0)
                {
                    PreserveStackTrace(ex);
                    throw;
                }
    
                Thread.Sleep(timeout);
            }
        }
        while (tries++ < retries);
    }
    
    /// <summary>
    /// Sets a flag on an <see cref="T:System.Exception"/> so that all the stack trace information is preserved 
    /// when the exception is re-thrown.
    /// </summary>
    /// <remarks>This is useful because "throw" removes information, such as the original stack frame.</remarks>
    /// <see href="http://weblogs.asp.net/fmarguerie/archive/2008/01/02/rethrowing-exceptions-and-preserving-the-full-call-stack-trace.aspx"/>
    public static void PreserveStackTrace(Exception ex)
    {
        MethodInfo preserveStackTrace = typeof(Exception).GetMethod("InternalPreserveStackTrace", BindingFlags.Instance | BindingFlags.NonPublic);
        preserveStackTrace.Invoke(ex, null);
    }
    

    당신은 그런 식으로 부를 것이다 :

    RetryBeforeThrow<SqlException>(() => MethodWhichFails(), 3, 100);
    
  5. ==============================

    5.이 같은 작업을 수행하기위한 좋은 스타일이 없습니다. 당신은 요청이 처음에 실패했지만 두 번째 성공 이유를 알아내는 것이 더 것입니다.

    이 같은 작업을 수행하기위한 좋은 스타일이 없습니다. 당신은 요청이 처음에 실패했지만 두 번째 성공 이유를 알아내는 것이 더 것입니다.

    SQL Server가 처음 실행 계획을 컴파일하고 쿼리를 실행하는 것이 가능 보인다. 그래서 첫 번째 호출이 결합 된 시간이 시간 제한 속성을 초과하기 때문에 실패하고 실행 계획이 이미 컴파일되어 저장되기 때문에 두 번째로 성공합니다.

    나는 UsersDataContext 어떻게 작동하는지 모르겠지만, 당신이 실제로 그것을 실행하기 전에 쿼리를 준비 할 수있는 옵션이있는 경우가 있습니다.

    실제 답변 : 나는이 작업을 수행해야한다면, 나는 다음과 같이 다시 한 번만이 아니라 다시 시도합니다 :

    var results = new List<UserSummaryDto>();
    using (var ctx = new 
        UsersDataContext(ConfigurationManager.ConnectionStrings[CONNECTION_STRING_KEY].ConnectionString))
    {
            try
            {
                results = ctx.SearchPhoneList(value, maxRows)
                             .Select(user => user.ToDto())
                             .ToList();
                break;
            }
            catch (SqlException)
            {
                try
                {
                    results = ctx.SearchPhoneList(value, maxRows)
                             .Select(user => user.ToDto())
                             .ToList();
                    break;
                }
                catch (SqlException)
                {
                    // set return value, or indicate failure to user however
                }
            }
        }
    }
    
    return results;
    

    난 당신이 재시도 프로세스를 남용하지 신뢰 수도 있지만, 당신은 빠른 수정으로 재시도 횟수를 증가 후임자를 유혹 할 것입니다.

  6. ==============================

    6.이 코딩 일부 인프라를 필요로하지만 나는 더 구조화 된 코드를 초래 재시도 횟수를 지정하는 측면과 방법을 주석 생각합니다.

    이 코딩 일부 인프라를 필요로하지만 나는 더 구조화 된 코드를 초래 재시도 횟수를 지정하는 측면과 방법을 주석 생각합니다.

  7. ==============================

    7.당신은 단순히 SQL 연결 재시도에 SqlConnectionStringBuilder의 속성을 사용할 수 있습니다.

    당신은 단순히 SQL 연결 재시도에 SqlConnectionStringBuilder의 속성을 사용할 수 있습니다.

    VAR conBuilder = 새 SqlConnectionStringBuilder ( "서버 =; 데이터베이스 = XXXX; Trusted_Connection = TRUE; MultipleActiveResultSets = 진정한"); conBuilder.ConnectTimeout = 90; conBuilder.ConnectRetryInterval = 15; conBuilder.ConnectRetryCount = 6;

    참고 : - 필수 닷넷 4.5 이상을.

  8. ==============================

    8.다음 재귀를 사용, 자신의 방법으로 관련 코드를 빼냅니다.

    다음 재귀를 사용, 자신의 방법으로 관련 코드를 빼냅니다.

    의사 코드 :

    try
    {
        doDatabaseCall();
    }
    catch (exception e)
    {
        //Check exception object to confirm its the error you've been experiencing as opposed to the server being offline.
        doDatabaseCall();
    }
    
  9. from https://stackoverflow.com/questions/4821668/what-is-good-c-sharp-coding-style-for-catching-sqlexception-and-retrying by cc-by-sa and MIT license