C#任务并行库和NHibernate / Spring.NET

时间:2011-01-07 09:34:49

标签: nhibernate task-parallel-library

我已经使用Spring.NET和NHibernate多年了,我非常满意。但是,我总是在玩多线程,Reactive Extensions以及最终的Task Parallel Library这是一个很棒的框架。不幸的是,由于NHiberntate的会话不是线程安全的,所有类型的多线程方法都会失败。

我问你如何从并行编程中受益并仍然使用NHibernate。

例如:我有一个CustomerRegistrationService类,方法Register执行几项任务:

ICustumer customer = this.CreateCustomerAndAdresses(params);
this.CreateMembership(customer);
this.CreateGeoLookups(customer.Address);
this.SendWelcomeMail(customer);

最后两种方法是理想的并行运行方式,CreateGeoLookups调用一些Web服务来确定客户地址的地理位置,并创建一些新实体以及更新客户本身。 SendWelcomMail做了它所说的。

因为CreateGeoLookups确实使用了NHibernate(尽管通过存储库对象,因此NHibernate通过接口/依赖性连接实际上是隐藏的),但它不能与Task.Factory.StarNew(...)或其他线程机制一起使用。 / p>

我的问题不是解决我所描述的这个问题,但我想听听您关于NHibenrate,Spring.NET和并行方法的信息。

非常感谢你 最大

3 个答案:

答案 0 :(得分:8)

在NH中它的ISession不是线程安全的,但ISessionFactory完全是线程安全的,很容易支持你所看到的。如果您已经设计了会话生命周期管理(以及依赖它的存储库),这样您就可以假设一个单一的ISession跨越调用,那么,是的,您将遇到这种麻烦。但是,如果您将会话处理模式设计为​​仅假设单个ISessionFactory而不是对ISession进行假设,则没有任何内在阻止您与NH并行进行交互。

虽然您没有特别提到您的用例是用于Web,但重要的是要注意以Web为中心的用例(例如,Spring.NET用户以及许多用户的常见情况)其他NH管理框架),经常使用的“Session-Per-Request”模式的ISession管理(在Spring.NET中通常被称为“Open Session in View”或只是'OSIV')将不起作用,你将需要切换到ISession生命周期的不同持续时间。这是因为(顾名思义)每个请求/ OSIV模式会使(在你的情况下现在不正确)假设在每个HttpRequest的持续时间内只有一个ISession实例(并且可能你想要成为产生这些并行的NH调用都在Web用例中的单个HttpRequest的上下文中。)

显然,在非网络案例中,每个请求的会话很少有类似的概念,因此会话生命周期管理很少像细粒度/短期一样存在,因此不太可能遇到此问题。它在基于网络的应用程序中。

希望这有帮助。

-Steve B。

答案 1 :(得分:2)

这是你要求的一件难事。 DTC必须小心谨慎。

我可能知道的唯一解决方案是使用可靠的事务性消息(例如MSMQ + NServiceBus / MassTransit)。

这样的设计使您能够这样做。它看起来像这样:

var customerUid=CreateCustomers(); 
Bus.Publish(new CustomerCreatedEvent() { CustomerUid = customerUid});

然后你可以使用两个处理事件的事件处理程序(Reactors)并发送电子邮件或创建查找。

这不允许您共享交易,但会确保在客户创建成功时运行Reactors(在新的Transaction中)。 这也与TPL无关。

答案 2 :(得分:0)

非常感谢您的回答。我知道'ISession不是线程安全的,但ISessionFactory完全是线程安全的'。我在上面的代码中的问题是例如整个操作包装在一个事务中。因此,主线程#1上的this.CreateCustomerAndAdresses(params)将使用例如事务#1的ISession#1。并行调用其他三个将创建另外三个线程和三个会话和事务,这导致我的情况下数据库超时。我的假设是事务#1未成功提交,因为它等待三个并发任务完成。但是,当事务仍处于活动状态时,三个并发任务会尝试从数据库中读取,从而导致死锁/超时。

那么是否有一些方法可以告诉其他线程/会话不要创建新事务但是使用主事务#1?

我正在使用Spring.NET的TxScopeTransactionManager,它使用DTC(System.Transactions)。我已经google了,可能System.Transactions.DependentTransaction可以工作,但不知道如何将它集成到我的Spring.NET事务管理场景中。

由于