如何在NHibernate中嵌套事务?
能做些什么NHibernate的嵌套事务,以及如何实现它们?我正在使用SQL Server 2008,所以支持绝对在DBMS中。如何在NHibernate中嵌套事务?
我觉得,如果我尝试这样:
using (var outerTX = UnitOfWork.Current.BeginTransaction())
{
using (var nestedTX = UnitOfWork.Current.BeginTransaction())
{
... do stuff
nestedTX.Commit();
}
outerTX.Commit();
}
那么到时候谈到outerTX.Commit()
交易已经变得不活跃,并导致在会话AdoTransaction一个的ObjectDisposedException。
难道我们因此应该代替创建嵌套NHibernate的会议?还是有一些其他类应该用来包装事务(我听说过TransactionScope,但我不确定那是什么)?
现在,我使用Ayende's UnitOfWork implementation(感谢Sneal)。
原谅在这个问题上任何的幼稚,我还是新来的NHibernate。
谢谢!
编辑:我发现,你可以使用的TransactionScope,如:
using (var transactionScope = new TransactionScope())
{
using (var tx = UnitOfWork.Current.BeginTransaction())
{
... do stuff
tx.Commit();
}
using (var tx = UnitOfWork.Current.BeginTransaction())
{
... do stuff
tx.Commit();
}
transactionScope.Commit();
}
但是我没有那么兴奋,这一点,因为它锁定在我们使用SQL Server和我也发现,如果数据库是远程的,那么你不得不担心MSDTC已启用......另外一个组件出错了。嵌套事务在SQL中非常有用且容易实现,我认为NHibernate会采用某种方式来模拟相同的...
如果要嵌套使用Ayende's UnitOfWork implementation,那么该实现不支持嵌套。您正在使用的实现(至少对于Web应用程序)的另一个问题是它在静态变量中占用ISession实例。
我昨天改写了我们的UnitOfWork由于这些原因,它最初是基于关闭加百列的。
我们不使用UnitOfWork.Current.BeginTransaction(),我们使用UnitofWork.TransactionalFlush(),它在最后创建一个单独的事务以一次刷新所有更改。
using (var uow = UnitOfWork.Start())
{
var entity = repository.Get(1);
entity.Name = "Sneal";
uow.TransactionalFlush();
}
是的,我觉得我应该从一开始就使用Rhino Commons ...我认为我和Gabriel一起去了,所以我可以从头开始构建单元工作模式(它确实帮助我理解了很多),但现在是时候和大男孩们一起玩了......感谢。 – Gavin 2009-07-28 16:34:28
我一直在努力与此一段时间了。我们会有另一个裂缝。
我想实现个性化服务容器的交易 - 因为这使他们自成一体 - 但是能够巢一堆更大事务中的服务方法,如果需要回滚一大堆。
因为我正在使用Rhino Commons我现在要尝试使用With.Transaction
方法进行重构。基本上,它允许我们编写代码,就好像事务是嵌套的,尽管实际上只有一个。
例如:
private Project CreateProject(string name)
{
var project = new Project(name);
With.Transaction(delegate
{
UnitOfWork.CurrentSession.Save(project);
});
return project;
}
private Sample CreateSample(Project project, string code)
{
var sample = new Sample(project, code);
With.Transaction(delegate
{
UnitOfWork.CurrentSession.Save(sample);
});
return sample;
}
private void Test_NoNestedTransaction()
{
var project = CreateProject("Project 1");
}
private void TestNestedTransaction()
{
using (var tx = UnitOfWork.Current.BeginTransaction())
{
try
{
var project = CreateProject("Project 6");
var sample = CreateSample(project, "SAMPLE006", true);
}
catch
{
tx.Rollback();
throw;
}
tx.Commit();
}
}
在Test_NoNestedTransaction()
,我们正在创建一个单独的项目,没有一个更大的交易的情况下。在这种情况下,在CreateSample
中将创建并提交新的事务,或者在发生异常时回滚。
在Test_NestedTransaction()
中,我们创建了一个样本和一个项目。如果出现任何问题,我们希望两者都回滚。实际上,CreateSample
和CreateProject
中的代码将运行,就好像根本没有交易一样;完全是外部事务决定是否回滚或提交,并根据是否抛出异常来完成。真的那就是为什么我要为外部事务使用手动创建的事务;所以我们可以控制是否提交或回滚,而不仅仅是默认为on-exception-rollback-else-commit。
你可以通过把一大堆这样的事情,通过代码实现无Rhino.Commons同样的事情:
if (!UnitOfWork.Current.IsInActiveTransaction)
{
tx = UnitOfWork.Current.BeginTransaction();
}
_auditRepository.SaveNew(auditEvent);
if (tx != null)
{
tx.Commit();
}
...等等。但With.Transaction
,尽管需要创建匿名代表的笨拙,这很方便。
这种方法相对于使用TransactionScope
(除了依赖MSDTC)的一个优点是,在最终的外部事务提交中应该只有一个数据库刷新,无论有多少方法被调用在两者之间。换句话说,我们不需要将未提交的数据写入数据库,因为我们总是将它写入本地NHibernate缓存。
简而言之,此解决方案不提供对您的交易的最终控制,因为它不会使用多个交易。我想我可以接受,因为无论如何,嵌套事务并不是每个DBMS都支持的。但是现在也许我至少可以编写代码而不必担心我们是否已经处于交易中。
NHibernate会话不支持嵌套事务。
下面的测试总是在2.1.2版本真:
var session = sessionFactory.Open();
var tx1 = session.BeginTransaction();
var tx2 = session.BeginTransaction();
Assert.AreEqual(tx1, tx2);
你需要将其包装在一个TransactionScope
支持嵌套事务。
MSDTC必须启用或者你会得到错误:
{"Network access for Distributed Transaction Manager (MSDTC) has been disabled. Please enable DTC for network access in the security configuration for MSDTC using the Component Services Administrative tool."}
由于萨蒂什建议,嵌套事务不NHibernate的支持。我还没有遇到需要嵌套事务的场景,但当然我遇到了一些问题,如果其他工作单元中的其他人已经处于活动状态,我必须忽略创建事务。
下面的博客链接提供了NHibernate的一个例子实施,也应该适用于SQL服务器: http://rajputyh.blogspot.com/2011/02/nested-transaction-handling-with.html
你已经能够找到答案?如何最终做嵌套事务? – learning 2010-07-20 10:23:58
@ user281180,有点。我找不到真正做到的方法,但你可以近似体验。在这里发表了博客:http://blog.constructionhive.com/2010/07/22/nested-transactions-and-nhibernate/ – Gavin 2010-07-22 00:19:12