这里有一些背景: 我们的网站会定期崩溃到不得不重新启动 IIS 的地步;这几乎总是在修补 DLL 的一个小时内发生(我们使用的是网站项目,而不是 Web 应用程序项目,因此每个 ASPX 页面都是一个单独的 DLL)。
在做一些研究时,我发现我们的自制 DAL 可以在调试时导致带有 Visual Studio 的内置网络服务器实际上停止工作并在它遇到存储过程中的 SQL 错误时被关闭(我的意思是它不仅抛出一个显示在浏览器中的异常,它实际上会说 Web 服务器出现错误,需要关闭!)
在进一步挖掘中,该错误似乎与 DAL 中所有内容(包括 Select 语句)的事务使用有关。似乎发生的是这样的:
- 尝试执行存储过程,存储过程由于缺少/无效列或其他错误而失败。
- 应用程序代码捕获错误并重新抛出它(不好,是的,但我没有写这个)。
- 尽管有异常,事务仍试图提交,得到一个
NullReferenceException
就transaction.Commit()
行了(似乎在Connection
属性上,因为有一个事务对象)。此外,这个 NullRef 似乎无法被捕获(我尝试了一个演示,该演示因无效的 Sproc 而强制崩溃,并且 NullRef 从未被捕获,即使输出错误将其类型为System.NullReferenceException
) - 事务引发错误,例如“事务已完成且不再可用”。
- ???但是 VS Web 服务器崩溃了。调试这部分似乎挂在上面的异常上,永远不会离开方法。
现在,我不知道这是否是导致 IIS 崩溃的原因,但它似乎很可疑,无论如何这都是一个明显的错误。
之前没有处理过事务并且只有它们的基本概念,我的第一个问题是为什么在抛出异常后事务仍然试图提交?我的第二个问题是如何修复失败的提交和可能无限循环的异常,直到服务器死机。添加这样的东西是否有意义(该方法采用名为 SqlTransaction 的参数transaction
):
catch (SqlException se)
{
if (transaction != null)
{
transaction.Rollback();
}
throw;
}
这个小改动会修复我认为导致 IIS 崩溃的持续异常循环吗?DAL 本身非常脆弱,具体用于数百个文件,因此我无法正确地从头开始重写它。
编辑整个代码块是这样的(同样,遗留代码 - 使用旧的微软数据访问块助手):
public static DataSet ExecuteDatasetStoredProc(SqlConnection conn, String storedProcName, SqlTransaction transaction, params SqlParameter[] storedProcParms)
{
try
{
// Execute the stored proc
if (transaction != null)
{
return SqlHelper.ExecuteDataset(transaction, CommandType.StoredProcedure, storedProcName, storedProcParms);
}
else
{
return SqlHelper.ExecuteDataset(conn, CommandType.StoredProcedure, storedProcName, storedProcParms);
}
}
catch (SqlException se)
{
throw new ApplicationException("Error calling " + storedProcName + ". " + se.Message, se);
}
}
但是,如果 catch 块执行事务仍会尝试提交,这似乎会导致挂起。