2012-06-19 27 views
8

Tôi đã phát triển một ứng dụng Giám sát. Vì vậy, tôi đã sử dụng một chức năng Timer để kiểm tra một số giá trị trong một bảng SQL.Giao dịch (Quy trình ID 84) bị bế tắc trên tài nguyên khóa với một quy trình khác và đã được chọn làm nạn nhân bế tắc

mặc dù có rất nhiều chức năng nó mang lại cho lỗi khi theo dõi cho một chức năng gọi là 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> 

Đây là việc thực hiện các chức năng

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(); 


      } 


     } 
    } 

Cảm ơn trước

+0

Bạn có thể muốn xem xét những đề nghị thực hiện trong câu trả lời này: http://stackoverflow.com/questions/2382410/sql-server-deadlock-fix-force-join-order-or-automatically-retry. Chúng tôi đã triển khai thành công truy vấn thử lại nếu truy vấn ban đầu bị bế tắc. – dash

+0

Ngoài ra, bạn đang viết bao nhiêu mục nhập nhật ký? Nếu bạn đang viết rất nhiều, nó có thể là bạn đang chỉ cản trở SELECT với một số lượng lớn INSERTS. – dash

+0

Bởi ứng dụng này không có gì được viết vào các bảng đó, nhưng phần mềm khác ghi dữ liệu vào các bảng đó. –

Trả lời

13

Bạn có thể tham khảo question để biết thêm một số đề xuất hữu ích khác.

Tôi sử dụng mẫu sau để thử lại cơ sở dữ liệu; trong trường hợp này, chúng ta trả về một DataTable nhưng mô hình là như nhau bất kể; bạn phát hiện SqlDeadlock hoặc Timeout dựa trên SqlException Number và thử lại, tối đa số lần n lầ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

Tôi hy vọng bạn đang theo dõi điều này. Ví dụ: nếu bạn nhận được một bế tắc thử lại mỗi triệu truy vấn hoặc mỗi tháng thì bạn vẫn ổn. Nếu bạn nhận được 1 phút, hoặc mọi truy vấn khác thì bạn gặp rắc rối và nên khắc phục nguyên nhân thay vì làm việc xung quanh nó ... – MatBailie

+0

@Dems Đôi khi bạn bị bế tắc nhưng bạn không muốn ứng dụng của mình chết vì của nó; thử lại mua bạn thời gian bạn cần để điều tra nguyên nhân gốc rễ của vấn đề; lưu ý rằng tôi khuyên bạn nên đọc liên kết đầu tiên :-) Đôi khi bạn cũng nhận được một bế tắc hoặc thời gian chờ chỉ vì hệ thống đang bận. – dash

+0

Tôi không nói không làm điều này, tôi chỉ nói để theo dõi nó. Như tôi đã nói, nếu nó không thường xuyên thì bạn tốt. Nhưng nếu nó thường xuyên thì bạn có một vấn đề và bạn đã buộc nó vào một sự im lặng - Tốt cho ứng dụng tại thời điểm đó, nhưng sau đó có nghĩa là bạn cần một số cách để theo dõi xem nó có xảy ra thường xuyên đến mức bạn thực sự cần phải giải quyết nguyên nhân cơ bản và không chỉ là hiệu ứng. Nếu bạn không theo dõi thì bạn thậm chí không biết có điều gì để điều tra. – MatBailie

3

Truy vấn của bạn bế tắc với một truy vấn khác. Truy vấn khác có nhiều khả năng là truy vấn insert, update hoặc delete, vì chỉ select không có xu hướng bế tắc.

Nếu bạn không quan tâm quá nhiều về tính nhất quán, bạn có thể sử dụng with (nolock) gợi ý:

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

Điều đó sẽ gây ra truy vấn của bạn không đặt ổ khóa. Một truy vấn không có khóa sẽ không gây ra deadlocks. Nhược điểm là nó có thể trả về dữ liệu không phù hợp, khi nó chạy cùng lúc với truy vấn sửa đổi.

+0

Lưu ý rằng nếu khóa đã leo thang tới Khóa bàn, điều này sẽ không hoạt động; xem http://msdn.microsoft.com/en-us/library/ms187373.aspx. – dash

+0

@dash: Bài viết đó chỉ áp dụng cho DDL, như 'thay đổi bảng', mà mua lại một khóa Sch-M (sửa đổi lược đồ). Một 'with (nolock)' sẽ vui vẻ đọc qua 'with (tablockx)' – Andomar

+0

"Hỗ trợ sử dụng các gợi ý READUNCOMMITTED và NOLOCK trong mệnh đề FROM áp dụng cho bảng đích của câu lệnh UPDATE hoặc DELETE sẽ được loại bỏ trong một Phiên bản tương lai của SQL Server. Tránh sử dụng các gợi ý này trong ngữ cảnh này trong công việc phát triển mới và lập kế hoạch sửa đổi các ứng dụng hiện đang sử dụng chúng. " cũng ở trong đó. Tôi không chắc chắn 100% rằng nó sẽ đọc qua một giao dịch trong mọi trường hợp; Tôi đã có tình huống mà nolock đã không làm việc vì một tablelock đã được đặt ra. – dash

Các vấn đề liên quan