当使用TransactionScope时,它表示如果内部执行的代码回滚事务,那么父事务也将回滚。这对我有好处。但是当处置该范围时,它会抛出异常,这意味着事务已经回滚并且已中止。 那么处理这个并正确处理范围的正确方法是什么?
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew))
{
using (var conn = GetConnection())
{
string query =
@"some query that may contain transaction itself
or some SP whith transaction included"
using (var command = new SqlCommand(query, conn))
command.ExecuteNonQuery();
}
}
scope.Complete();
} // Exception here
答案 0 :(得分:6)
scope.Dispose()
被调用, TransactionAborted
也可能会抛出scope.Complete()
例外。例如,一些足够聪明的存储过程可以使用T-SQL TRY/CATCH
构造w/o
向调用者抛出异常来处理T-SQL脚本中的异常和中止事务。
所以我认为我建议的最安全的方法如下:
try
{
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew))
{
try
{
using (var conn = GetConnection())
{
string query =
@"some query that may contain transaction itself
or some SP whith transaction included"
using (var command = new SqlCommand(query, conn))
command.ExecuteNonQuery();
}
}
catch (SqlException ex)
{
// log SQL Exception, if any
throw; // re-throw exception
}
scope.Complete();
}
}
catch (TransactionAbortedException ex)
{
// we can get here even if scope.Complete() was called.
// log TransactionAborted exception if necessary
}
不要担心处置TransactionScope
。 scope.Dispose在抛出TransactionAborted
异常之前执行任何必要的清理工作。
答案 1 :(得分:0)
如果从内部查询抛出异常,则scope.Complete()行将不会执行。 请参考下面的链接..我也对您的查询进行了一些更改。我希望它适合你。 Transaction Scope
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew))
{
using (var conn = GetConnection())
{
string query =
@"some query that may contain transaction itself
or some SP whith transaction included"
using (var command = new SqlCommand(query, conn))
command.ExecuteNonQuery();
}
scope.Complete();
}
答案 2 :(得分:0)
我不使用存储过程或特定于SQL的try / catch,所以我的情况略有不同,但我得到了帖子中提到的完全相同的事务中止异常。我发现如果我在主TransactionScope内部有一个SELECT,那将导致事务提交,虽然我不知道为什么。我有一个案例,为了在数据库中创建一个对象,它首先检查以确保该对象不存在SELECT,然后在调用Dispose时发生中止异常。我查看了内部异常,它说交易试图在没有开始的情况下提交。我终于尝试在Suppressed TransactionScope中包装我的SELECT,然后它工作了。所以:
using(TransactionScope tx = new TransactionScope())
{
//UPDATE command for logging that I want rolled back if CREATE fails
using(TransactionScope tx2 = new TransactionScope(TransactionScopeOption.Suppress))
{
// SELECT command
}
//If not exists logic
//CREATE command
} //Used to error here, but not with the SELECT Suppressed
我希望这可以帮助其他可能在不使用存储过程的情况下获得此异常的人。