2012-06-19 6 views
8

모니터링 애플리케이션을 개발했습니다. 그래서 거기에 SQL 테이블의 일부 값을 확인하려면 타이머 함수를 사용했습니다. 이렇게 많은 기능이 있기는하지만트랜잭션 (프로세스 ID 84)이 다른 프로세스와 잠금 리소스에 교착 상태가되어 교착 상태 희생자로 선택되었습니다.

그것은 getLogEntry라는 하나 개의 기능에 대한 다음과 같은 오류()

message>Transaction (Process ID 84) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.</message> 
<innerMessage> 
</innerMessage> 
<source>.Net SqlClient Data Provider</source> 
<stackTrace>at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection) 
    at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj) 
    at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) 
    at System.Data.SqlClient.SqlDataReader.HasMoreRows() 
    at System.Data.SqlClient.SqlDataReader.ReadInternal(Boolean setTimeout) 
    at ShiftAlertSystem.DBAccess.getLogEntry(Int32 nEventLogIdn, connections cn)</stackTrace> 
    <createdAt>2012/06/18 13:10:47</createdAt> 

이 사전에

public LogEntry getLogEntry(int nEventLogIdn, connections cn) 
    { 
     lock (_objLock) 
     { 
      LogEntry lgEntObj = new LogEntry(); 
      SqlConnection NewCon3 = new SqlConnection(); 
      SqlCommand newCmd2 = null; 
      SqlDataReader dr = null; 

      try 
      { 


       string connectString; 
       // Configuration config = ConfigurationManager.u 
       string DataSource = cryptIT.Decrypt(cn.DataSource_bio); 
       string initialCatalog = cryptIT.Decrypt(cn.InitialCatalog_bio); 
       string user = cryptIT.Decrypt(cn.user_bio); 
       string password = cryptIT.Decrypt(cn.password_bio); 
       bool intergratedSecurity = cn.IntegratedSecurity_bio; 

       if (intergratedSecurity) 
       { 
        connectString = "Data Source=" + DataSource + ";Initial Catalog=" + initialCatalog + ";Integrated Security=True"; 
       } 
       else 
       { 
        connectString = "Data Source=" + DataSource + ";Initial Catalog=" + initialCatalog + ";User ID=" + user + ";Password=" + password; 
       } 

       NewCon3 = new SqlConnection(connectString); 
       NewCon3.Open(); 



       newCmd2 = NewCon3.CreateCommand(); 
       newCmd2.Connection = NewCon3; 
       newCmd2.CommandType = CommandType.Text; 
       newCmd2.CommandText = @" 
           SELECT [nUserID] 
             ,[sUserName] 
             ,dateadd(s,[nDateTime],'1970/1/1') AS LogDateTime 
             ,[nEventIdn] 
             ,[nTNAEvent] 
             ,[TB_READER].[nReaderIdn] 
             ,[sName] 
           FROM 
             [TB_EVENT_LOG] 
             ,[TB_USER] 
             ,[TB_READER] 
           WHERE 

             [nEventLogIdn] = " + nEventLogIdn + 
             @" AND 
             [TB_EVENT_LOG].[nUserID] = [TB_USER].[sUserID] 
             AND 
             [nFlag]= 1 
             AND 
             [TB_EVENT_LOG].[nReaderIdn]=[TB_READER].[nReaderIdn]" 
             ; 
       dr = newCmd2.ExecuteReader(); 

       if (dr != null && dr.Read()) 
       { 
        lgEntObj.nUserID = dr.GetInt32(0); 
        lgEntObj.nUserName = dr.GetString(1); 
        lgEntObj.LogDateTime = dr.GetDateTime(2); 
        lgEntObj.nEventIdn = dr.GetInt32(3); 
        lgEntObj.nTNAEvent = dr.GetInt16(4); 
        lgEntObj.nReaderIdn = dr.GetInt32(5); 
        lgEntObj.sName = dr.GetString(6); 
       } 
       dr.Close(); 
       newCmd2.Dispose(); 
       // NewCon.Close(); 
       NewCon3.Close(); 

       return lgEntObj; 
      } 
      catch (Exception exc) 
      { 
       CenUtility.ErrorLog.CreateLog(exc); 
       return null; 
      } 

      finally 
      { 
       if (dr != null) 
        dr.Close(); 

       if(newCmd2 != null) 
        newCmd2.Dispose(); 


        NewCon3.Close(); 


      } 


     } 
    } 

감사 기능의 구현을 제공

+0

당신이 대답했다 제안을 고려할 수 있습니다 http://stackoverflow.com/questions/2382410/sql-server-deadlock-fix-force-join-order-or-automatically-retry합니다. 원래 쿼리가 교착 상태 인 경우 쿼리 재 시도가 성공적으로 구현되었습니다. – dash

+0

또한 몇 개의 로그 항목을 쓰고 있습니까? 많은 글을 쓰고 있다면, 많은 INSERT로 SELECT를 방해하고있는 것일 수 있습니다. – dash

+0

이 응용 프로그램에서는 이러한 테이블에 아무 것도 기록되지 않지만 다른 소프트웨어는 해당 테이블에 데이터를 씁니다. –

답변

13

좀 더 유용한 제안 사항은 question을 참조하십시오.

데이터베이스 재시도에 다음 패턴을 사용합니다. 이 경우 DataTable을 반환하지만 패턴은 상관없이 동일합니다. SqlException을 기반으로 SqlDeadlock 또는 Timeout을 검색 한 다음 최대 n 회까지 다시 시도하십시오.

public DataTable DoSomeSql(int retryCount = 1) 
    { 
     try 
     { 
      //Run Stored Proc/Adhoc SQL here 

     } 
     catch (SqlException sqlEx) 
     { 
      if (retryCount == MAX_RETRY_COUNT) //5, 7, Whatever 
      { 
       log.Error("Unable to DoSomeSql, reached maximum number of retries."); 
       throw; 
      } 

      switch (sqlEx.Number) 
      { 
       case DBConstants.SQL_DEADLOCK_ERROR_CODE: //1205 
        log.Warn("DoSomeSql was deadlocked, will try again."); 
        break; 
       case DBConstants.SQL_TIMEOUT_ERROR_CODE: //-2 
        log.Warn("DoSomeSql was timedout, will try again."); 
        break; 
       default: 
        log.WarnFormat(buf.ToString(), sqlEx); 
        break; 
      } 

      System.Threading.Thread.Sleep(1000); //Can also use Math.Rand for a random interval of time 
      return DoSomeSql(asOfDate, ++retryCount); 
     } 
    } 
+3

나는 이것을 모니터링하고 싶습니다. 예를 들어 매 쿼리마다 또는 한 달에 한 번 교착 상태가 발생하면 괜찮습니다. 1 분마다 또는 다른 모든 쿼리를 얻는다면 문제가 생겨서 그 원인을 해결해야합니다. – MatBailie

+0

@Dems 때때로 교착 상태에 빠지기는하지만 애플리케이션이 죽는 것을 원하지 않기 때문에 그것의; 다시 시도하면 문제의 근본 원인을 조사해야 할 때가 있습니다. 첫 번째 링크를 읽는 것이 좋습니다 :-) 때로는 시스템이 사용 중이므로 교착 상태 또는 시간 초과가 발생할 수도 있습니다. – dash

+0

나는이 일을하지 말라고 말하는 것이 아니며, 나는 단지 그것을 모니터하는 것입니다. 내가 말했듯이 드문 경우라면 당신은 훌륭합니다. 그러나 정기적 인 경우 문제가 있으며 침묵의 오류가 발생했습니다. 그 시점에서 앱에 좋았지 만 실제로 자주 발생하는지 여부를 모니터링 할 수있는 방법이 필요합니다. 근본적인 원인이 아니라 그것의 효과. 모니터하지 않으면 조사 할 것이 있다는 것을 알지도 못합니다. – MatBailie

3

검색어가 다른 검색어로 인해 교착 상태입니다. 다른 쿼리는 insert, update 또는 delete 쿼리 일 가능성이 높습니다. 이는 select만으로 교착 상태가 발생하지 않기 때문입니다.

FROM 
    [TB_EVENT_LOG] with (nolock) 
    ,[TB_USER] with (nolock) 
    ,[TB_READER] with (nolock) 

잠금을하지 쿼리를 발생합니다 : 당신은 일관성에 대해 너무 많이 걱정하지 않는 경우

, 당신은 with (nolock) 힌트를 사용할 수 있습니다. 잠금이없는 쿼리는 교착 상태를 발생시키지 않습니다. 단점은 수정 쿼리와 동시에 실행될 때 일관성없는 데이터를 반환 할 수 있다는 것입니다.

+0

잠금 장치가 테이블 잠금 장치로 올라가면이 기능은 작동하지 않습니다. http://msdn.microsoft.com/ko-kr/library/ms187373.aspx를 참조하십시오. – dash

+0

@ 대시 :이 기사는 Sch-M (스키마 수정) 잠금을 얻는'alter table'과 같은 DDL에만 적용됩니다. 'with (nolock)'은'with (tablockx)' – Andomar

+0

"을 통해 행복하게 읽을 수 있습니다. UPDATE 또는 DELETE 문의 대상 테이블에 적용되는 FROM 절의 READUNCOMMITTED 및 NOLOCK 힌트 사용에 대한 지원은 SQL Server의 차기 버전입니다.이 컨텍스트에서 새로운 개발 작업에서 이러한 힌트를 사용하지 말고 현재 사용하고있는 응용 프로그램을 수정할 계획입니다. " 그것도 있습니다. 모든 경우에 트랜잭션을 통해 읽을 수 있는지 100 % 확신 할 수는 없습니다. 테이블 잠금 장치가 제자리에 있었기 때문에 놀크가 작동하지 않는 상황이있었습니다. – dash

관련 문제