使用带有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)]
的目的还是错误?
我一直在深入研究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
...
来自Castle专家/所有者的人可以检查一下吗?
答案 0 :(得分:2)
作者在这里,
我认为你的代码很棒,并且如果它没有打破其他测试,它会合并PR。 =)
RequiresNew不受支持的原因是因为它在99%的情况下都是反模式。在将您的工作单元封装在交易中之后,您就可以了;并且您的工作单元应与业务操作1-1相对应。
现在,如果您在当前主题上进行了交易,就像您在需要使用“需要新内容”的情况下一样,那么您在阅读脏话之后数据或产生不相关的事务(从业务操作的角度来看)。因此,你应该在另一个线程中这样做。
由于交易是“环境问题”。并且在C#这样的编程语言的控制流程中没有明确表示,你留下了你的调用上下文插槽&#39;保存交易参考;但从你的代码的角度来看,这些并不存在;你所拥有的是仅在事务上下文中工作的部分函数。如果你产生第二个交易;你打算如何与当前交易协调?这很难;并可能导致问题。
在其他交易系统中,例如geteventstore.com,您会获得一个显式的事务标识符 - 您在System.Transactions中也有一个,但它在API / ABI / ADO.Net中没有明确的数据库因此你不能以同样的方式使用它。使用明确的交易标识符,您可以在遇到疑问时解决失败,即“将军问题”。你不能使用System.Transactions。相反,您必须在有问题的DTC上安装事务MMC并手动回滚或转发。