我有一个针对 SQL Server 2012 运行的 C# OLTP 应用程序。我希望它在其数据库位于 AlwaysOn 可用性组中时发生故障转移时不会中断运行。为了从因故障转移而中断的事务中恢复,我使用另一个类 (RetryableSqlCommand) 包装了 C# SqlCommand 对象,该类捕获与故障转移相关的异常(连接断开、无法强化远程事务等)并自动重试它们在指数退避延迟之后。在小型测试应用程序中,此代码完全按照我的意愿工作。当在完整的 OLTP 应用程序中以中等负载(每秒几百个事务)运行时,我在手动故障转移数据库时遇到错误。
该错误总是发生在插入一个主记录和 4 个详细记录的最常调用的存储过程之一中。存储过程始终将插入的主记录和详细记录的 ID 作为 OUTPUT 参数返回。C# 代码如下所示:
using (RetryableSqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = "InsertComplexItem";
cmd.CommandType = CommandType.StoredProcedure;
// add sproc input parameters for master and detail records
await cmd.ExecuteNonQueryAsync();
// retrieve IDs of inserted records
var masterId = (long)(cmd.Parameters["MasterId"].Value); <-- InvalidCastException
var detail1Id = (long)(cmd.Parameters["Detail1Id"].Value);
var detail2Id = (long)(cmd.Parameters["Detail2Id"].Value);
var detail3Id = (long)(cmd.Parameters["Detail3Id"].Value);
var detail4Id = (long)(cmd.Parameters["Detail4Id"].Value);
}
我在上面提到的那一行得到了一个 InvalidCastException,因为我从调试日志中确定,ID 是作为 DBNulls 从存储过程返回的。据我所知,这永远不会发生,因为存储过程将所有记录插入到单个事务中。如果事务被中断,应该会有一个异常被 RetryableSqlCommand 类捕获并重试。InvalidCastException 的任何解释?