C# .net嵌套事务范围

C# .net嵌套事务范围,c#,transactionscope,C#,Transactionscope,我们认为我们理解transactionscope和嵌套(transactionscope.requires)-即 ------------------------------------------------------- 内|外| ------------------------------------------------------- 提交|回滚|未提交任何更改 提交|提交|提交所有更改 回滚|回滚|未提交任何更改 回滚(提交)不起作用---- 然而,我想知道,是否有任何方法可以创建t

我们认为我们理解transactionscope和嵌套(transactionscope.requires)-即

------------------------------------------------------- 内|外| ------------------------------------------------------- 提交|回滚|未提交任何更改 提交|提交|提交所有更改 回滚|回滚|未提交任何更改 回滚(提交)不起作用---- 然而,我想知道,是否有任何方法可以创建transactionscope、嵌套transactionscope、依赖事务、自定义事务或其他任何东西,其中回滚提交场景也可以工作


也就是说,在库函数中有一些东西,不管出于什么原因,它都有自己的事务,它位于父事务之下。如果内部事务成功,则外部事务可以访问任何更改,但如果内部事务回滚,则外部事务仍处于完全可用状态,并且完全不受内部事务的影响,好像从未调用过一样?

否,我相信您认为这是错误的。它仍然只是一个事务,只是嵌套允许感兴趣的代码块投票决定事务是否应该成功(无需传递事务对象),而不是创建嵌套事务。这就是transactionscope上的方法被称为Complete而不是Commit的原因

编辑以处理OP中的评论

为了得到您想要的,我认为您必须创建两个TS对象,第二个带有RequiresNew,然后根据需要完成/回滚每个对象。我不知道第一个事务是否会看到第二个事务的更改,您必须自己进行实验,看看TS是否可以在这里提供帮助

我理解你想做什么,我并不是说你这样做是错误的;如果这是您的用例所需要的,那么这就是它所需要的

然而,我不相信TS是为这个用例设计的,我认为引用嵌套事务的文档是不幸的,因为它并不像通常讨论的那样(比如在TSQL中)是真正的嵌套事务


TS是为更常见的用例而设计的,其中组件A和B都做事务性工作,A使用B作为其工作的一部分,但B也可以独立使用。TS允许B始终是事务性的,无论是独立使用还是作为A工作的一部分,并且启动事务或重用A(因为A是UoW),而不必传递事务对象。

不作为事务范围

如果您的事务都是针对数据库资源管理器的(这是托管TransactionScope的绝大多数用途),那么您可以利用数据库功能。数据库支持事务保存点。实际实现因数据库而异,让我们谈谈SQL Server

您可以直接在T-SQL中利用事务保存点,例如,请参见:

此过程模板允许在异常情况下进行优雅的恢复,允许在外部工作继续并提交时回滚内部工作

您可以在托管代码中执行相同的操作,如使用和


但是,System.Transactions API不支持这些操作。这并不奇怪,考虑到系统的主要角色之一。事务是管理分布式事务(多个RM),但数据库事务保存点与分布式事务不兼容。

您在这里要求的应该得到直接支持,IMHO,但显然不是。我同意。-我们已经解决了这个问题,但在这一点上,它更像是一种智力上的好奇心——也就是说,真的有可能让它像那样工作吗?我想使用一个继承的作用域,重写dispose,这样它只会记住它,但是下一段代码会看到数据库,就像你提交了事务一样——或者有某种神奇的方式捕获它,然后再创建另一个事务作用域,但之后您将丢失在此之前发生的一切。这是一个相当有趣的问题!我认为您将数据库事务(有助于强制执行数据一致性和原子更改)与工作单元之类的东西混淆了。从数据一致性的角度来看:如果外部依赖于内部(即内部嵌套在外部),那么在内部回滚之后,您将永远不希望继续。如果不是这种情况,外部并不依赖于内部。在这种情况下,嵌套事务是用于执行任务的错误工具。通过重构,您通常可以以更好的方式获得所需的结果:使用顺序事务(非嵌套)、抢占式检查(如果内部将通过)等。a)从理论上理解,但我只想知道是否可以做到-正确的嵌套事务-b)仅仅因为某个组件出现故障,这并不意味着我总是想让整个事情失败,c)主要问题是它让交易处于一种不可靠的状态,因此,失败后的一切。
仅仅因为我们认为某些事情不应该做,就没有理由不去看我们是否能够找到解决方法。@Darrenakey我在我的答案中添加了我希望澄清的内容。将内部事务处理范围设置为RequiresNew是实现目标的方法。但是,根据本文,“在使用TransactionScopeOption.RequiresNew值时,应该非常小心,并验证两个事务(环境事务和为您的范围创建的事务)在一个中止而另一个提交时不会引入不一致。”@AaronHawkins我认为RequiresNew本身不会自动满足OP的要求;一旦内部事务将其作为独立事务提交。如果外部事务失败,则无法回滚该事务,这是TSQL嵌套事务会发生的情况。 ------------------------------------------------------- inner | outer | ------------------------------------------------------- commit | rollback | no changes are committed commit | commit | all changes are committed rollback | rollback | no changes are committed rollback | commit | ---- doesn't work ----
create procedure [usp_my_procedure_name]
as
begin
    set nocount on;
    declare @trancount int;
    set @trancount = @@trancount;
    begin try
        if @trancount = 0
            begin transaction
        else
            save transaction usp_my_procedure_name;

        -- Do the actual work here

lbexit:
        if @trancount = 0   
            commit;
    end try
    begin catch
        declare @error int, @message varchar(4000), @xstate int;
        select @error = ERROR_NUMBER(), @message = ERROR_MESSAGE(), @xstate = XACT_STATE();
        if @xstate = -1
            rollback;
        if @xstate = 1 and @trancount = 0
            rollback
        if @xstate = 1 and @trancount > 0
            rollback transaction usp_my_procedure_name;

        raiserror ('usp_my_procedure_name: %d: %s', 16, 1, @error, @message) ;
    end catch   
end
go