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

时间:2014-07-09 21:26:00

标签: 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");
    }
}

如图所示使用

using(var scope = new TransactionScope())
using(new WtfTransactionScope())
{
    scope.Complete();
}

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

  

处理完毕
  准备叫做   承诺
  准备完成

WUT。

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

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

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

1 个答案:

答案 0 :(得分:14)

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

我会让你烦恼使它漂亮,但一个显而易见的方法是:

using(var wtf = new WtfTransactionScope())
using(var scope = new TransactionScope())
{
    wtf.Initialize();
    scope.Complete();
}

Prepare completed只是一个无用的调试语句。只需将其删除即可。