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

C#任务并行库和NHibernate/Spring.NET,nhibernate,task-parallel-library,Nhibernate,Task Parallel Library,我已经使用Spring.NET和NHibernate好几年了,我非常满意。然而,我一直在玩弄多线程、反应式扩展以及最终的任务并行库,这是一个很棒的框架。不幸的是,所有类型的多线程方法都失败了,因为NHiberntate的会话不是线程安全的 我在问你我如何从并行编程中获益,并且仍然使用NHibernate 例如:我有一个CustomerRegistrationService类,该类方法Register执行多个任务: ICustumer customer = this.CreateCustomerA

我已经使用Spring.NET和NHibernate好几年了,我非常满意。然而,我一直在玩弄多线程、反应式扩展以及最终的任务并行库,这是一个很棒的框架。不幸的是,所有类型的多线程方法都失败了,因为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通过接口/依赖项InAction实际上是隐藏的),所以它不适用于Task.Factory.StarNew(…)或其他线程机制

我的问题不是要解决我所描述的这个问题,而是想听听您对NHibenrate、Spring.NET和并行方法的看法

多谢各位
Max

在NH中,ISession不是线程安全的,但是ISessionFactory是完全线程安全的,很容易支持您想要的。如果您将会话生命周期管理(以及依赖于它的存储库)设计为跨调用使用一个一致的ISession,那么,是的,您将遇到这种问题。但是,如果您将会话处理模式设计为只假设一个ISessionFactory,而不假设ISession,那么就没有什么内在的因素阻止您与NH并行交互

虽然您没有特别提到您的用例是针对web的,但重要的是要注意,在以web为中心的用例中(例如,对于Spring.NET用户以及许多其他NH管理框架来说,这是一种非常常见的情况),通常使用的ISession管理的“每请求会话”模式(在Spring.NET中通常称为“视图中的开放会话”或仅称为“OSIV”)将不起作用,您需要切换到ISession生命周期的不同持续时间。这是因为(顾名思义)每个请求的会话/OSIV模式会使假设在每个HttpRequest的持续时间内只有一个ISession实例(假设您希望在web用例中的单个HttpRequest上下文中生成这些并行NH调用)

显然,在非web的情况下,很少有类似于每个请求会话的概念,因此您不太可能遇到此问题,因为会话生命周期管理很少像基于web的应用程序中那样细粒度/短暂

希望这有帮助


-Steve B.

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

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

我使用的是Spring.NET中的TxScopeTransactionManager,它使用DTC(System.Transactions)。我在谷歌上搜索到System.Transactions.DependentTransaction可能会工作,但不知道如何将其集成到我的Spring.NET事务管理场景中


谢谢

这是您要求的一件困难的事情。必须小心处理DTC

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

这样的设计使您能够做到这一点。它将如下所示:

var customerUid=CreateCustomers(); 
Bus.Publish(new CustomerCreatedEvent() { CustomerUid = customerUid});
然后,您可以使用两个事件处理程序(反应器)来处理事件并发送电子邮件或创建查找

这也不允许您共享事务,但将确保在成功创建客户时(在新事务中)运行反应器。
此外,这与第三方物流无关。

对于所述问题,我实际上认为这是一种更明智的方法。您不会因为无法创建地理数据或发送电子邮件而不创建客户,而是希望在完成这两个过程之前重试。这非常适合邮件eue架构。你真的应该用这个问题来编辑你的主要问题。这些问题都可以作为答案吗?