2016-11-08 151 views
1

在將此問題標記爲重複項之前,以下是我不明白的棘手部分。這個錯誤是零星的,我相信代碼是正確的,它總是在工作,我正在處理Reader部分內部的if else條件可能出現的錯誤。下面是代碼:代碼未同步拋出索引超出界限數組?

public static Tuple<int, string> GetIDAndString(string term) 
{ 
    try 
    { 
     using (SqlConnection con = GetConnection()) 
     using (cmd = new SqlCommand()) 
     using (myReader) 
     { 
      int ID = 0; 
      string status = string.Empty; 
      cmd.Connection = con; 
      con.Open(); 
      cmd.CommandText = @"SELECT t.TableID, t.Status 
           FROM Table t WITH (NOLOCK) /* I know NOLOCK is not causing the mistake as far as I know */ 
           WHERE t.Term = @term"; 
      cmd.Parameters.AddWithValue("@term", term); 

      myReader = cmd.ExecuteReader(); 
      while(myReader.Read()) 
      { 
       ID = myReader.IsDBNull(0) ? 0 : myReader.GetInt32(0); 
       status = myReader.IsDBNull(1) ? string.Empty : myReader.GetString(1).Trim(); 
      } 

      myReader.Close(); 

      return new Tuple<int, string>(ID, status); 
     } 
    } 
    catch (Exception) 
    { 
     throw; 
    } 
} 

我知道我應該使用,而不是一個元組的一類,但我不能改變現有的代碼,你可以看到。所以主要的問題是在生產服務器中有一個Index out of bounds array exception這種方法,但我不能確定是什麼問題。

即使在查詢中找不到該術語,myReader也不會進入,我將返回ID = 0,status = string.Empty。有時,當我在調試代碼並在develpment server上工作時,我的代碼開始在任何地方崩潰,向我展示異常情況,在哪裏測試代碼,我必須重新打開解決方案以避免這種情況(我還沒找到解決方案,甚至沒有清洗溶液)。

所以我希望有人在production server有類似的經驗。我沒有生產服務器的規格,所以我對服務器一無所知。

+0

創建新數據讀取不分享!這可能會給你帶來問題! – mybirthname

+0

不要同意以前的評論,要麼創建新的實例,要麼同步對它的訪問。 –

+0

@mybirthname,我是編程新手,你說不要共享dataReader。你的意思是不使用類聲明受保護的靜態SqlDataReader,然後在使用塊中使用它? –

回答

1

首先你不需要try/catch塊,你不用做任何事情。之後,不要在課堂上分享SqlDataReader,這可能會帶來問題,並可能由此產生問題。您在此期間一直覆蓋IDStatus的值。一個好主意可能是在您的查詢中調用Top 1,並通過正確的字段進行排序。也沒有必要Dispose()SqlCommandSqlCommand的構造函數調用SupressFinalization()

爲什麼會出現此問題:設想您的查詢返回1000條包含TableIDStatus列的記錄,並且您正在輸入while循環。在這一刻,其他一些用戶正在進入您的應用程序並執行另一種方法,即覆蓋SqlDataReader並返回5條只有一列的記錄。在你循環的下一個迭代中,你會收到你的異常。因此,你不應該把你的讀者定義爲static。靜態變量在所有應用程序用戶之間共享。

public static Tuple<int, string> GetIDAndString(string term) 
{ 
    int ID = 0; 
    string status = string.Empty; 

    using (SqlConnection con = GetConnection()) 
    { 
     SqlCommand cmd = new SqlCommand(); 
     cmd.Connection = con; 
     con.Open(); 

     cmd.CommandText = @"SELECT t.TableID, t.Status 
          FROM Table t WITH (NOLOCK) /* I know NOLOCK is not causing the mistake as far as I know */ 
          WHERE t.Term = @term"; 
     cmd.Parameters.AddWithValue("@term", term); 


     using(SqlDataReader myReader = cmd.ExecuteReader()) 
     { 
      while(myReader.Read()) 
      { 
       ID = myReader.IsDBNull(0) ? 0 : myReader.GetInt32(0); 
       status = myReader.IsDBNull(1) ? string.Empty : myReader.GetString(1).Trim(); 
      } 

     } 

    } 

    return new Tuple<int, string>(ID, status); 
} 
+0

很好的解釋!我會給你正確的答案,因爲它與其他的一樣,但以我的代碼和最佳實踐爲例。只有其他的事情希望你能爲我澄清。如果我在'GetConnection()'方法中使用'protected static SqlTransaction',我應該像在類中的SqlReader一樣進行更改嗎?或僅僅用於SqlReader?謝謝 –

+0

@JorgeF是不要使用靜態事務。檢查msdn文章:https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqltransaction(v=vs.110).aspx。 – mybirthname

+0

謝謝,我會做出這些變化 –

0

這可能發生在您執行ID = myReader.IsDBNull(0) ? 0 : myReader.GetInt32(0);status = myReader.IsDBNull(1) ? string.Empty : myReader.GetString(1).Trim();時,因爲結果集不符合您的期望。您應該在實際閱讀之前添加閱讀器行的日誌記錄,可能會幫助您查明問題

0

using (myReader)捕捉到讀者當時擁有的價值和配置。它不記得變量。從這個例子中你可以看到:using (Random() ? myReader : null)。顯然,C#語言在處理時不會重新執行該表達式。它只運行一次。

所以你正在處置一些舊的/其他的讀者。

如果你正在線程之間共享對象(也許使用靜態變量),這個普通的情況就是競爭條件。不要這樣做。使用當地人。這裏沒有必要/有優勢使用靜態變量。