为什么 - 如何 - 处理后处理交易?

9 c# idisposable transactionscope

我正在尝试使用一些环境事务范围(谢谢,),我以前没有真正做过,而且我看到了一些......我想要理解的奇怪行为.

我正在尝试登记当前的事务范围,并在成功完成后做一些工作.我的征兵参与者IDisposable由于拥有一些资源而实施.我有一个展示奇怪行为的简单例子.

对于这堂课,

class WtfTransactionScope : IDisposable, IEnlistmentNotification
{
    public WtfTransactionScope()
    {
        if(Transaction.Current == null)
            return;
        Transaction.Current.EnlistVolatile(this, EnlistmentOptions.None);
    }
    void IEnlistmentNotification.Commit(Enlistment enlistment)
    {
        enlistment.Done();
        Console.WriteLine("Committed");
    }

    void IEnlistmentNotification.InDoubt(Enlistment enlistment)
    {
        enlistment.Done();
        Console.WriteLine("InDoubt");
    }

    void IEnlistmentNotification.Prepare(
        PreparingEnlistment preparingEnlistment)
    {
        Console.WriteLine("Prepare called");
        preparingEnlistment.Prepared();
        Console.WriteLine("Prepare completed");
    }

    void IEnlistmentNotification.Rollback(Enlistment enlistment)
    {
        enlistment.Done();
        Console.WriteLine("Rolled back");
    }

    public void Dispose()
    {
        Console.WriteLine("Disposed");
    }
}
Run Code Online (Sandbox Code Playgroud)

当按照这里说明使用时

using(var scope = new TransactionScope())
using(new WtfTransactionScope())
{
    scope.Complete();
}
Run Code Online (Sandbox Code Playgroud)

控制台输出演示了wtf-ness:

Disposed
Prepare称为
承诺
准备完成

武汉理工大学.

我在交易完成之前就已经处理好了.这种......否定了挂起交易范围的好处.我希望一旦交易成功(或不成功),我就会得到通知,这样我就可以做一些工作了.不幸的是我假设scope.Complete()在我离开using范围之后,当我被处理之前和之后会发生这种情况.显然事实并非如此.

当然,我可以破解它.但我有其他问题基本上阻止我这样做.在这种情况下,我将不得不废弃并做其他事情.

我在这里做错了吗?或者这是预期的行为?可以采取不同的措施来防止这种情况发生吗?

Han*_*ant 14

这是自己造成的痛苦.您违反了IDisposable的一个非常基本的规则,只有在其他任何地方不再使用时,才应该处置该对象.当您的using语句调用Dispose()时,它正在使用,您在WtfTransactionScope构造函数中提交了对象的引用.在完成它之前你不能处置它,这必然意味着你必须在TransactionScope的using语句完成并且事务被提交/回滚之后处理它.

我会让你担心它变得漂亮,但一个显而易见的方法是:

using(var wtf = new WtfTransactionScope())
using(var scope = new TransactionScope())
{
    wtf.Initialize();
    scope.Complete();
}
Run Code Online (Sandbox Code Playgroud)

Prepare completed只是一个无益的调试声明.只需删除它.

  • 另外,请注意 Complete 不会提交事务。它仅将范围标记为已完成。事实上,只有当另一个外部作用域完成 * 并且 * 被释放时,才可能提交事务。(今天的选票用完了。) (2认同)