2009-05-19 99 views
4

我有一個查詢,應該總是返回一個int。我現在記錄它返回一個完全無關的字符串。爲什麼我的SqlCommand應該是一個int時返回一個字符串?

我們已經得到了一些隨機的FormatExceptions,我們已經追蹤了幾個數據庫查詢。經過一些額外的日誌記錄後,我發現,今天上午,下面的查詢返回了字符串「角鬥士」。 Website.PkID是一個i​​nt列,大多數情況下都是可用的,但有時它會慘敗,並返回一個int值(比任何有效的WebsiteID大)或一個隨機字符串。

此特定查詢在每個會話開始時被擊中一次。它沒有使用共享連接,所以我無法理解如何得到這樣的混合結果。連接池中是否存在某種腐敗?

我不認爲問題是孤立於此查詢。我也看到了來自LINQ查詢的類似的FormatExceptions(因爲意外的結果)。我們也在同一時間發現了一些這些錯誤:

A transport-level error has occurred when sending the request to the server. (provider: TCP Provider, error: 0 - An existing connection was forcibly closed by the remote host.

它可能是連接問題嗎?或者,也許我們正在將數據庫服務器和Web服務器之間的結果集混淆起來?這真讓我撓了撓頭。

犯規查詢:

public static int GetActiveWebSiteID(string storeID, string statusID) 
{ 
    int retval; 

    string sql = @"SELECT isnull(MAX(PkID),0) FROM WebSite 
        WHERE StoreID = @StoreID 
        AND WebSiteStatusID = @WebSiteStatusID"; 

    SqlConnection conn = new SqlConnection(Settings.ConnString); 
    SqlCommand cmd = new SqlCommand(sql, conn); 
    cmd.CommandType = CommandType.Text; 
    cmd.Parameters.AddWithValue("@StoreID", (object)storeID ?? DBNull.Value); 
    cmd.Parameters.AddWithValue("@WebSiteStatusID", (object)statusID ?? DBNull.Value); 

    conn.Open(); 
    using(conn) 
    { 
     var scalar = cmd.ExecuteScalar(); // <-- This value returned here should only ever be an int, but randomly is a string 

     retval = Convert.ToInt32(scalar); 
    } 
    return retval; 
} 

上面的查詢一直很好了多年,直到最近。我們現在在應用程序中有一堆額外的LINQ查詢(不知道這是否有所不同)。我們正在運行.Net 3.5。

+0

'標量'的值是什麼字符串? – 2009-05-19 13:43:50

+0

可能是字符串,當它爲「0」時MAX(PkID)爲空 – TheVillageIdiot 2009-05-19 13:45:36

+0

如前所述,我看到登錄錯誤的字符串是「角鬥士」。我有一種預感,它與來自系統某處的其他查詢結果有某種混淆,特別是關鍵字搜索。但我還不能證明這一點。 – 2009-05-19 15:14:53

回答

9

忽略這個問題幾個月後,它開始以達到臨界質量作爲流量逐漸增大。我們增加了日誌記錄並發現了許多確定性實例,在重負載下,完全不同的結果集將返回到無關的查詢。

我們觀察了Profiler中的查詢並能夠看到不良結果始終與同一個spid關聯,並且每個錯誤結果始終都是查詢實際sql語句後面的一個查詢。這就像結果集被錯過了,並且返回了spid中下一個結果集(來自同一個池中的另一個連接)。瘋。

通過試驗和錯誤,我們最終追蹤了一些SqlCommand或LINQ查詢,其SqlConnection在使用後沒有立即關閉。相反,通過一些源於對LINQ連接誤解的拙劣編程,DataContext對象僅在請求結束時才被處理(並關閉連接),而不是立即處理。

一旦我們重構這些方法立即關閉與C#「using」塊的連接(爲下一個請求釋放該池),我們不會再收到任何錯誤。雖然我們仍然不知道連接池會混淆的根本原因,但我們能夠停止所有類型的錯誤。這個問題與我發佈的另一個類似錯誤結合解決,發現在這裏:What Causes "Internal Connection Fatal Errors"?

1

ExecuteScalar()函數的返回類型是object,並且用var關鍵字聲明結果變量。這不是一個很好的組合,因爲你在系統上施加很大的壓力才能獲得正確的類型推斷。

+0

該列是一個int,結果是一個「角鬥士」字符串。我不明白類型推斷與此有什麼關係。 int列或其任何聚合不應返回字符串。 – 2009-05-19 14:24:00

+2

類型推斷不應該產生「角鬥士」:) – VVS 2009-05-19 17:19:26

+2

也不應該發佈代碼,除非PkID不是真正的int列。 – 2009-05-19 17:32:29

1

我認爲你是想sqlCommand.ExecuteNonQuery返回受影響的一個int值中的行數...

這是ExecuteScalar方法的定義:

public override object ExecuteScalar() 
Member of System.Data.SqlClient.SqlCommand 

摘要:

執行查詢,返回查詢返回的結果集中第一行的第一列。其他列或行將被忽略。

返回:

第一行的在結果集中的第一列,或空引用(Visual Basic中爲Nothing)如果結果集是空的。

所以,我認爲返回該列的常用方式是作爲列值的字符串表示形式。

0

字段「PkID」是「WebSite」表中的varchar/char。

如果查詢的「ISNULL」部分爲真,那麼它將返回一個整數(0),否則它會返回一個字符串「PKID」

0

可能有不止一個網站目錄的價值。你能證明你的表架構名稱:

SELECT ISNULL(MAX(PKID),0)YourSchema.WebSite WHERE STOREID = @StoreID AND WebSiteStatusID = @WebSiteStatusID

0

有什麼共性,當它無法返回一個int?

由於您的查詢只返回單行中的單個列,因此如果您使用更安全的ExecuteReader並獲取第一列的值,您會得到什麼結果?

它總是返回一排嗎?如果WHERE子句導致它不返回任何行(說你的參數不是你認爲的那些行),那麼ISNULL不會生效 - 根本沒有行,並且ExecuteScalar應該返回一個NULL。

1

我最近看到一個代碼意外切換連接字符串的情況。出於診斷目的,請硬編碼連接字符串並查看問題是否消失。

而且,理智的緣故,請使用使用塊像嵌套:

using(SqlConnection conn = new SqlConnection("hard-coded connection string")) 
{ 
    using (SqlCommand cmd = new SqlCommand(sql, conn)) 
    { 
     // more init 
     object scalar = cmd.ExecuteScalar(); 

     // process result 
    } 
} 

它不會讓我感到吃驚發現有兩個數據庫實例,並於一體,PKID是int,在另一個是VARCHAR。


看一下SQL Profiler,看看你是否能夠趕上「角鬥士」的回報。在另一個我正在使用的例子中,SQL事件探查器什麼都沒有顯示,表明實際的查詢是去了一個不同的數據庫。

0

我認爲您的發佈查詢和LINQ都不是問題。

你確定你正在尋找正確的來源嗎?如何調用該方法?記錄如何完成?

Select isn't broken.

0

我假設Settings.ConnString從Web.Config中或註冊表中讀取和重新使用其他靜態例程。在你的例程中調用cmd.ExecuteScalar()之前執行第二種方法會在連接上修改cmd.CommandText時,是否有可能存在計時問題?

希望這有助於

比爾

相關問題