C# 回滚外部 TransactionScope 而不管嵌套 TransactionScopes 中发生了什么
C# Rollback Outer TransactionScope Regardless of What Happens In Nested TransactionScopes
首先,我看过这个类似的问题:Nested/Child TransactionScope Rollback但是答案没有提供解决方案,我们的问题也略有不同。
基本上,我有一个使用事务作用域的数据库集成测试(实际上,作用域是在 setup/teardown 中抽象管理的 class)
[Test]
public void MyTest()
{
using(var outerScope = new TransactionScope())
{
Assert.True(_myService.MyMethod());
var values = _myService.AnotherMethod();
}
}
并且MyService.MyMethod也使用了TransactionScope
public bool MyMethod()
{
using(var innerScope = new TransactionScope())
using(var con = conFact.GetOpenConnection())
{
var cmd = con.CreateCommand();
//set up and execute command
if (isCheck) scope.Complete();
return isCheck;
}
}
所以理论上,如果 isCheck 为真,MyMethod 只会提交它的更改,但无论该事务是否提交,当方法被测试时,它都会被回滚。
它按预期工作,除非 isCheck 为假,在这种情况下我得到以下异常:System.Transactions.TransactionException : The operation is not valid for the state of the transaction.
我认为这里发生的事情是因为innerScope使用了TransactionScopeOption.Required,它加入了outerScope中使用的事务。一旦 innerScope 在 isCheck 为 false 时被释放,outerScope 也会被释放(这是我不想发生的事情!)所以当我在调用 MyMethod 后尝试获得另一个连接时,outerScope 已经被释放。
或者,如果我指定 TransactionOption.RequiresNew,我会得到这个异常:System.Data.SqlClient.SqlException : Timeout expired.
我已经尝试使用具有指定保存点的 SqlTransaction 和 TransactionOption 的不同组合都无济于事。
没有嵌套事务这样的东西。您可以嵌套范围,但嵌套范围所做的只是附加已经 运行 的事务。您不能独立于其他范围来处理内部范围(当然 RequiresNew 除外,它只是创建一个独立的事务)。
您想要的功能在 System.Transactions
中不存在。
保存点是创建类似嵌套事务的唯一方法。但是话又说回来 SQL 服务器很容易因为任意原因终止你的整个交易。什么错误回滚语句,什么错误回滚事务是不可预测的。 (是的,这没有意义。)
首先,我看过这个类似的问题:Nested/Child TransactionScope Rollback但是答案没有提供解决方案,我们的问题也略有不同。
基本上,我有一个使用事务作用域的数据库集成测试(实际上,作用域是在 setup/teardown 中抽象管理的 class)
[Test]
public void MyTest()
{
using(var outerScope = new TransactionScope())
{
Assert.True(_myService.MyMethod());
var values = _myService.AnotherMethod();
}
}
并且MyService.MyMethod也使用了TransactionScope
public bool MyMethod()
{
using(var innerScope = new TransactionScope())
using(var con = conFact.GetOpenConnection())
{
var cmd = con.CreateCommand();
//set up and execute command
if (isCheck) scope.Complete();
return isCheck;
}
}
所以理论上,如果 isCheck 为真,MyMethod 只会提交它的更改,但无论该事务是否提交,当方法被测试时,它都会被回滚。
它按预期工作,除非 isCheck 为假,在这种情况下我得到以下异常:System.Transactions.TransactionException : The operation is not valid for the state of the transaction.
我认为这里发生的事情是因为innerScope使用了TransactionScopeOption.Required,它加入了outerScope中使用的事务。一旦 innerScope 在 isCheck 为 false 时被释放,outerScope 也会被释放(这是我不想发生的事情!)所以当我在调用 MyMethod 后尝试获得另一个连接时,outerScope 已经被释放。
或者,如果我指定 TransactionOption.RequiresNew,我会得到这个异常:System.Data.SqlClient.SqlException : Timeout expired.
我已经尝试使用具有指定保存点的 SqlTransaction 和 TransactionOption 的不同组合都无济于事。
没有嵌套事务这样的东西。您可以嵌套范围,但嵌套范围所做的只是附加已经 运行 的事务。您不能独立于其他范围来处理内部范围(当然 RequiresNew 除外,它只是创建一个独立的事务)。
您想要的功能在 System.Transactions
中不存在。
保存点是创建类似嵌套事务的唯一方法。但是话又说回来 SQL 服务器很容易因为任意原因终止你的整个交易。什么错误回滚语句,什么错误回滚事务是不可预测的。 (是的,这没有意义。)