我有一个查询,总是返回一个int。我现在已经记录了它返回一个与它本应完全无关的字符串。
我们已经获得了一些随机的FormatExceptions,我们已经跟踪了几个数据库查询。经过一些额外的日志记录后,我发现今天早上,下面的查询返回了字符串“gladiator”。 Website.PkID是一个int列,大部分时间都可以工作,但有时它会失败并且返回一个int(那里有大于任何有效的WebsiteID)或随机字符串。
每个会话开始时会触发一次此特定查询。它没有使用共享连接,所以我很难理解它是如何得到这样的混合结果的。连接池中是否会出现某种损坏?
我认为这个问题与此查询无关。我也看到了来自LINQ查询的类似的FormatExceptions(因为意外的结果)。我们也在同一时间发现了一些错误:
将请求发送到服务器时发生传输级错误。 (提供者:TCP提供者,错误:0 - 远程主机强制关闭现有连接。
可能是连接问题吗?或者我们可能在数据库服务器和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 :(得分:9)
在忽略了这个问题几个月之后,随着流量逐渐增加,它开始达到临界质量。我们增加了日志记录并发现了许多确定的实例,在这些实例中,在负载很重的情况下,完全不同的结果集将返回到不相关的查询。
我们在Profiler中查看了查询,并且能够看到错误的结果始终与相同的spid相关联,并且每个错误的结果总是在查询的实际sql语句后面的一个查询。这就像一个结果集被遗漏了,并且返回了spid中的下一个结果集(来自同一个池中的另一个连接)。疯狂。
通过反复试验,我们最终找到了一些SqlCommand或LINQ查询,这些查询的SqlConnection在使用后没有立即关闭。相反,通过一些源于对LINQ连接的误解的草率编程,DataContext对象仅在请求结束时而不是立即处理(并且连接关闭)。
一旦我们重构这些方法以立即关闭与C#“使用”块的连接(为下一个请求释放该池),我们就不再收到错误。虽然我们仍然不知道连接池会如此混淆的根本原因,但我们能够停止此类错误。此问题已与我发布的另一个类似错误一起解决,可在此处找到:What Causes "Internal Connection Fatal Errors"?
答案 1 :(得分:1)
ExecuteScalar()函数的返回类型为object
,并使用var
关键字声明结果变量。这不是一个很好的组合,因为你在系统上施加了很大的压力来正确地进行类型推理。
答案 2 :(得分:1)
我认为您正在考虑sqlCommand.ExecuteNonQuery
返回int值中受影响的行数...
这是ExecuteScalar方法的定义:
public override object ExecuteScalar()
Member of System.Data.SqlClient.SqlCommand
<强>要点:强>
执行查询,返回查询返回的结果集中第一行的第一列。其他列或行将被忽略。
<强>返回:强>
结果集中第一行的第一列,如果结果集为空,则为空引用(在Visual Basic中为Nothing)。
所以,我认为返回该列的常用方法是作为列值的字符串表示。
答案 3 :(得分: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事件探查器查看是否可以捕获“角斗士”的回归。在我正在使用的另一种情况下,SQL Profiler根本没有显示任何内容,表明实际的查询是进入不同的数据库。
答案 4 :(得分:0)
字段“PkID”是“WebSite”表中的varchar / char。
如果查询的“ISNULL”部分为真,那么它将返回一个整数(0),否则它将返回一个值为“PkID”的字符串
答案 5 :(得分:0)
可能有多个WebSite表。您可以使用模式名称限定表:
SELECT isnull(MAX(PkID),0)FROM YourSchema.WebSite WHERE StoreID = @StoreID AND WebSiteStatusID = @WebSiteStatusID
答案 6 :(得分:0)
当它无法返回int时是否有任何共性?
由于您的查询只返回单行中的单个列,如果您使用更多类型安全的ExecuteReader并获取第一列的值,您会得到什么?
它总是连续返回吗?如果WHERE
子句导致它没有返回任何行(假设您的参数不是您认为的那样),则ISNULL
不会生效 - 根本没有行,而ExecuteScalar是应该返回NULL。
答案 7 :(得分:0)
答案 8 :(得分:0)
我假设从Web.Config或注册表中读取Settings.ConnString,并重用其他静态例程。是否有可能存在一个计时问题,即在例程中调用cmd.ExecuteScalar()之前执行第二个方法,该例程修改了连接上的cmd.CommandText?
希望这有帮助,
比尔