在使用带有Castle.Facilities.AutoTx属性的[Transaction(TransactionScopeOption.RequiresNew)]工具时,不会创建预期的新System.Transactions.CommittableTransaction。
您可以轻松地使用以下单元测试来测试它
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)中更改下面的代码来修复这种行为
if (activity.Count == 0)
tx = new Transaction(new CommittableTransaction(new TransactionOptions
...至
if (activity.Count == 0 || transactionOptions.Mode == TransactionScopeOption.RequiresNew)
tx = new Transaction(new CommittableTransaction(new TransactionOptions
...城堡专家/业主的人能检查一下吗?
发布于 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上,并手动回滚或转发。
https://stackoverflow.com/questions/25143954
复制相似问题