C# · 12月 23, 2021

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

我已经使用 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(…)或其他线程机制一起使用.

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

非常感谢你@H_403_15@马克斯

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

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

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

希望这可以帮助.

-Steve B.