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

6

我已经使用Spring.NET和NHibernate有一段时间了,并且我非常满意。然而,我一直在尝试着使用多线程、响应式扩展和最终的任务并行库,这是一个很好的框架。不幸的是,由于NHiberntate的会话(session)不是线程安全的,所有种类的多线程方法都会失败。

我想问您如何从并行编程中受益,同时仍然利用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(...) 或其他线程机制。
我的问题不是解决我所描述的问题,而是我想听听您对 NHibenrate、Spring.NET 和并行方法的看法。
非常感谢 Max
3个回答

8
在NH中,ISession不是线程安全的,但ISessionFactory完全是线程安全的,很容易支持您所需的功能。如果您设计了会话生命周期管理(以及依赖于它的存储库),并假设在调用之间有一个单一一致的ISession,则确实会遇到此类问题。但是,如果您设计了会话处理模式,仅假定单个ISessionFactory而不对ISession进行假设,则没有任何固有的阻止您与NH并行交互的东西。
尽管您没有明确提及您的用例是用于Web,但重要的是要注意,在面向Web的用例中(例如,这是Spring.NET用户以及许多其他NH管理框架的常见情况),经常使用的ISession管理“每请求一个会话”模式(通常在Spring.NET中称为“打开视图中的会话”或只是“OSIV”)将无法工作,您需要切换到不同的ISession生命周期。这是因为(正如名称所示),每请求一个会话/OSIV模式使(现在在您的情况下不正确的)假设为每个HttpRequest的持续时间仅有一个ISession实例(并且可能您希望在Web用例的上下文中生成这些并行NH调用,所有这些都在单个HttpRequest中)。
显然,在非Web案例中,很少有类似于每请求一个会话的概念,因此您不太可能遇到此问题,因为会话生命周期管理很少像Web应用程序中那样细粒度/短暂。
希望这可以帮助您。
-Steve B.

2
这是一个比较困难的翻译任务。DTC需要小心处理。
我所知道的唯一解决方案就是使用可靠的事务性消息传递(例如MSMQ + NServiceBus/MassTransit)。
这种设计可以让您实现此目标,其结构如下:
var customerUid=CreateCustomers(); 
Bus.Publish(new CustomerCreatedEvent() { CustomerUid = customerUid});

那么你可以使用两个事件处理程序(反应器)来处理事件并发送电子邮件或创建查找。

这不会允许您分享交易,但会确保在客户创建成功时运行反应器(在新事务中运行)。 此外,这与TPL无关。


针对所述问题,我实际上认为这是更明智的方法。您不会因为无法创建地理数据或发送电子邮件而不创建客户,而是希望重试这些过程,直到它们完成。这完全符合消息队列架构。 - Geoff Bennett

0
非常感谢您的回答。我知道“ISession不是线程安全的,但ISessionFactory完全是线程安全的”。我在上面的示例代码中的问题是整个操作都包装在一个事务中。因此,在主线程#1上创建客户和地址(参数)将使用例如带有事务#1的ISession#1。同时调用其他三个方法会创建三个更多的线程和三个更多的会话和交易,这会导致我的情况下出现数据库超时。我假设事务#1没有成功提交,因为它等待三个并发任务完成。但是,三个并发任务尝试在事务仍处于活动状态时从数据库读取,导致死锁/超时。

那么,有没有办法告诉其他线程/会话不要创建新事务,而是使用主事务#1?

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

谢谢


你真的应该编辑你的主问题,将这个问题加入其中。这些答案中有没有一个可作为答案? - crthompson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接