我在申请中遇到了一次错误。
此SQLTransaction已完成;它不再可用了
下面附有堆栈跟踪 - 它说明了Zombie Check
和Rollback
。
代码中的错误是什么?
注意:此错误只出现一次。
更新
来自MSDN - SqlTransaction.Rollback Method
如果连接已终止或者事务已在服务器上回滚,则Rollback会生成InvalidOperationException。
来自Zombie check on Transaction - Error
我在各种应用程序中看到此错误的最常见原因之一是,在我们的应用程序中共享 SqlConnection。
CODE
public int SaveUserLogOnInfo(int empID)
{
int? sessionID = null;
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlTransaction transaction = null;
try
{
transaction = connection.BeginTransaction();
sessionID = GetSessionIDForAssociate(connection, empID, transaction);
//Other Code
//Commit
transaction.Commit();
}
catch
{
//Rollback
if (transaction != null)
{
transaction.Rollback();
transaction.Dispose();
transaction = null;
}
//Throw exception
throw;
}
finally
{
if (transaction != null)
{
transaction.Dispose();
}
}
}
return Convert.ToInt32(sessionID,CultureInfo.InvariantCulture);
}
堆栈跟踪
参考:
答案 0 :(得分:7)
注意:此错误只出现一次。
然后很难说出来;可能只是// Other Code
等只是花了很长时间,整个事情都被杀死了。也许你的连接已经死亡,或者管理员故意将其杀死,因为你正在阻止它。
代码中的错误是什么?
过度复杂化;它可以更简单:
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
using(var transaction = connection.BeginTransaction())
{
try
{
sessionID = GetSessionIDForAssociate(connection, empID, transaction);
//Other Code
transaction.Commit();
}
catch
{
transaction.Rollback();
throw;
}
}
}
更少的代码出错。
答案 1 :(得分:6)
你应该把一些工作留给编译器,把它包装在try
/ catch
/ finally
中给你。
此外,如果Rollback
阶段出现问题,或者与服务器的连接中断,您应该期望Commit
偶尔会抛出异常。因此,您应将其包装在try
/ catch
。
try
{
transaction.Rollback();
}
catch (Exception ex2)
{
// This catch block will handle any errors that may have occurred
// on the server that would cause the rollback to fail, such as
// a closed connection.
Console.WriteLine("Rollback Exception Type: {0}", ex2.GetType());
Console.WriteLine(" Message: {0}", ex2.Message);
}
这完全是从MSDN documentation page for Rollback method复制的。
我发现你担心你有一个僵尸交易。如果你粘贴了,听起来不像你有问题。您的交易已经完成,您不应该再与它有任何关系了。如果你拿着它们就删除对它的引用,并忘记它。
来自MSDN - SqlTransaction.Rollback Method
如果连接已终止或者事务已在服务器上回滚,则Rollback会生成InvalidOperationException。
重新抛出一个新例外,告诉用户数据可能尚未保存,并请她刷新并查看
答案 2 :(得分:2)
我使用下面的代码可以重现此错误,我使用1000个任务来执行Sql,在大约300个任务成功完成后,timeout error
开始出现很多关于ExecuteNonQuery()
的例外,
然后在This SqlTransaction has completed
上发生下一个错误transaction.RollBack();
,其调用堆栈也包含ZombieCheck()
。
(如果1000个任务的单个程序压力不够,可以同时执行多个编译的exe文件,甚至可以使用多台计算机执行一个数据库。)
所以我猜其中一个导致此错误的原因可能是Connection出错了,导致事务错误也会发生。
Task[] tasks = new Task[1000];
for (int i = 0; i < 1000; i++)
{
int j = i;
tasks[i] = new Task(() =>
ExecuteSqlTransaction("YourConnectionString", j)
);
}
foreach (Task task in tasks)
{
task.Start();
}
/////////////
public void ExecuteSqlTransaction(string connectionString, int exeSqlCou)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlCommand command = connection.CreateCommand();
SqlTransaction transaction;
// Start a local transaction.
transaction = connection.BeginTransaction();
// Must assign both transaction object and connection
// to Command object for a pending local transaction
command.Connection = connection;
command.Transaction = transaction;
try
{
command.CommandText =
"select * from Employee";
command.ExecuteNonQuery();
// Attempt to commit the transaction.
transaction.Commit();
Console.WriteLine("Execute Sql to database."
+ exeSqlCou);
}
catch (Exception ex)
{
Console.WriteLine("Commit Exception Type: {0}", ex.GetType());
Console.WriteLine(" Message: {0}", ex.Message);
// Attempt to roll back the transaction.
try
{
transaction.Rollback();
}
catch (Exception ex2)
{
// This catch block will handle any errors that may have occurred
// on the server that would cause the rollback to fail, such as
// a closed connection.
Console.WriteLine("Rollback Exception Type: {0}", ex2.GetType());
Console.WriteLine(" Message: {0}", ex2.Message);
}
}
}
}
此外,我发现如果我提交两次sequentail也会调用此异常。
transaction.Commit();
transaction.Commit();
或者,如果在提交之前Connection Connection也调用此错误。
connection.Close();
transaction.Commit();
<强>更新强>
我觉得很奇怪,我创建了另一个新表并向其插入了50万个数据,
然后使用select * from newtable
sql执行100000个任务,同时运行5个程序,这次发生超时错误,但是transaction.Rollback()
时它没有调用SQLTransaction has completed error
。< / p>
但如果发生超时错误,请跳转到catch块,然后在catch块再次执行transaction.Commit()
,SQLTransaction has completed error
将会发生。
答案 3 :(得分:1)
我曾经历过这个错误,我被困住了,无法知道出了什么问题。实际上我正在删除一条记录,在存储过程中,我没有删除它的孩子,特别是Stored Procedure
中的删除语句在Transaction
边界内。我从存储过程中删除了该事务代码,并且摆脱了“This SqlTransaction has completed; it is no longer usable.”
答案 4 :(得分:0)
这条消息只是因为您编写的代码在事务已成功提交后抛出异常。请尝试检查您在Commit方法后编写的代码或您可以使用Try..Catch处理它,最后使用Blocks :)。