[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.나는 특정 오류 만 재 시도에 예외 처리를 변경할 것입니다 :
나는 특정 오류 만 재 시도에 예외 처리를 변경할 것입니다 :
다음은 기본 "다시 시도"오류입니다
catch (SqlException ex) { if !(ex.Number == 1205 || ex.Number == 1204 || ... ) { throw } retryCount++; if (retryCount > MAX_RETRY) throw; }
당신은 SQL 상자를 망치하지 않도록 편집, 나는 대기 잊어 청소 :
편집 2 :
나는 많은 C #을하지 마십시오 개발자 DBA입니다. 내 대답은 통화에 대한 올바른 예외 처리했다 ...
-
==============================
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.이 같은 SQL 외모에 대한 retryables 내 열거 :
이 같은 SQL 외모에 대한 retryables 내 열거 :
SqlConnectionBroken = -1, SqlTimeout = -2, SqlOutOfMemory = 701, SqlOutOfLocks = 1204, SqlDeadlockVictim = 1205, SqlLockRequestTimeout = 1222, SqlTimeoutWaitingForMemoryResource = 8645, SqlLowMemoryCondition = 8651, SqlWordbreakerTimeout = 30053
-
==============================
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.이 같은 작업을 수행하기위한 좋은 스타일이 없습니다. 당신은 요청이 처음에 실패했지만 두 번째 성공 이유를 알아내는 것이 더 것입니다.
이 같은 작업을 수행하기위한 좋은 스타일이 없습니다. 당신은 요청이 처음에 실패했지만 두 번째 성공 이유를 알아내는 것이 더 것입니다.
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.이 코딩 일부 인프라를 필요로하지만 나는 더 구조화 된 코드를 초래 재시도 횟수를 지정하는 측면과 방법을 주석 생각합니다.
이 코딩 일부 인프라를 필요로하지만 나는 더 구조화 된 코드를 초래 재시도 횟수를 지정하는 측면과 방법을 주석 생각합니다.
-
==============================
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.다음 재귀를 사용, 자신의 방법으로 관련 코드를 빼냅니다.
다음 재귀를 사용, 자신의 방법으로 관련 코드를 빼냅니다.
의사 코드 :
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(); }
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
'SQL' 카테고리의 다른 글
[SQL] 가게 순위 위치로 MySQL의 업데이트 문 (0) | 2020.06.27 |
---|---|
[SQL] 고유 번호 생성에는 mysql (0) | 2020.06.27 |
[SQL] 여러 테이블에서 INSERT INTO 표 (0) | 2020.06.27 |
[SQL] 내가 한 번 사용 후 왜 내 CTE에 액세스 할 수 없습니다? (0) | 2020.06.27 |
[SQL] 행 사이 SQL 차이 (0) | 2020.06.27 |