2009-05-19 122 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时,是否有可能存在计时问题?

希望这有助于

比尔

相关问题