首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用[Transaction(TransactionScopeOption.RequiresNew)]时,Castle.Facilities.AutoTx不会启动新的可提交事务

使用[Transaction(TransactionScopeOption.RequiresNew)]时,Castle.Facilities.AutoTx不会启动新的可提交事务
EN

Stack Overflow用户
提问于 2014-08-05 16:32:13
回答 1查看 219关注 0票数 2

在使用带有Castle.Facilities.AutoTx属性的[Transaction(TransactionScopeOption.RequiresNew)]工具时,不会创建预期的新System.Transactions.CommittableTransaction

您可以轻松地使用以下单元测试来测试它

代码语言:javascript
复制
using System.Transactions;
using Castle.Facilities.AutoTx.Testing;
using Castle.MicroKernel.Registration;
using Castle.Transactions;
using Castle.Windsor;
using NUnit.Framework;

namespace Castle.Facilities.AutoTx.Tests
{
    public class TransService
    {
        private readonly NewTransService _s2;

        public TransService(NewTransService s2)
        {
            _s2 = s2;
        }

        [Transaction]
        public virtual string DoInTrans()
        {
            var currentTransaction = System.Transactions.Transaction.Current;
            Assert.That(currentTransaction != null, "The current transaction mustn't be null.");
            string transId = currentTransaction.TransactionInformation.LocalIdentifier;

            _s2.DoInNewTrans(transId);

            return transId;
        }
    }

    public class NewTransService
    {
        [Transaction(TransactionScopeOption.RequiresNew)]
        public virtual string DoInNewTrans(string parentTransId)
        {
            var currentTransaction = System.Transactions.Transaction.Current;
            Assert.That(currentTransaction != null, "The current transaction mustn't be null.");
            string transId = currentTransaction.TransactionInformation.LocalIdentifier;

            Assert.AreNotEqual(parentTransId, transId, "Ambient transaction must differ from parent");

            return transId;
        }
    }

    public class SingleThread_NewAmbient
    {
        private WindsorContainer _Container;

        [SetUp]
        public void SetUp()
        {
            _Container = new WindsorContainer();
            _Container.AddFacility<AutoTxFacility>();
            _Container.Register(Component.For<TransService>());
            _Container.Register(Component.For<NewTransService>());
        }

        [TearDown]
        public void TearDown()
        {
            _Container.Dispose();
        }

        [Test]
        public void Automatically_Starts_New_CommitableTransaction()
        {
            using (var scope = new ResolveScope<TransService>(_Container))
                scope.Service.DoInTrans();
        }

    }
}

我是误解了[Transaction(TransactionScopeOption.RequiresNew)]的目的,还是它是一个bug?

我一直在深入研究Castle.Transactions源代码,并且能够通过在Castle.Transactions.TransactionManager.ITransactionManager.CreateTransaction(ITransactionOptions transactionOptions)中更改下面的代码来修复这种行为

代码语言:javascript
复制
if (activity.Count == 0)
    tx = new Transaction(new CommittableTransaction(new TransactionOptions
    ...

代码语言:javascript
复制
if (activity.Count == 0 || transactionOptions.Mode == TransactionScopeOption.RequiresNew)
    tx = new Transaction(new CommittableTransaction(new TransactionOptions
    ...

城堡专家/业主的人能检查一下吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-08-06 14:29:26

这里的作者,

我认为你的代码很棒,如果它不破坏其他测试的话,它会将PR和它合并。=)

RequiresNew没有得到很好的支持是因为在99%的案例中它是反模式的。您需要在事务中封装您的工作单元;您的工作单元应该与应该一致的业务操作对应1-1。

现在,如果您在当前线程上运行一个事务,就像您需要使用'RequiresNew‘一样,那么您要么是在读取脏数据,要么是生成一个无关的事务(从业务运营的角度来看)。因此,您应该在另一个线程中这样做。

由于在像C#这样的编程语言中,事务在控制流中是“环境”的,所以您可以使用“调用上下文槽”来保存事务引用;但是从代码的角度来看,这些不存在;您拥有的是只在事务性上下文中工作的部分函数。如果您生成了第二个事务,您将如何与当前事务进行协调?这很难,而且很可能导致问题。

旁白

在其他事务性系统中,比如geteventstore.com,您获得了一个显式事务标识符--在System.Transactions中也有一个,但是它在API/ABI/ADO.Net中对数据库不明确,因此您不能以同样的方式使用它。有了一个明确的事务标识符,当它变得“可疑”时,您可以解决失败,即“将军问题”;您不能使用System.Transactions。相反,您必须将事务MMC挂载到有问题的DTC上,并手动回滚或转发。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25143954

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档