C # Task Parallel Library and NHibernate / Spring.NET

I have been using Spring.NET and NHibernate for several years, and I am very pleased. However, I always played with multi-threaded, reactive extensions and, ultimately, with a parallel task library, which is an excellent foundation. Unfortunately, all kinds of multithreaded approaches fail because of an NHiberntate session that is not thread safe.

I ask you how I can use parallel programming and still use NHibernate.

For example: I have a class CustomerRegistrationService , the Register method performs several tasks:

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

The last two methods are ideal candidates for parallel work, CreateGeoLookups calls some web services to determine the geographical location of the client’s address and creates some new objects, as well as updates the client itself. SendWelcomMail does what it says.

Since CreateGeoLookups uses NHibernate (although through repository objects, therefore NHibernate is hidden covertly through Interfaces / Dependency Inection), it will not work with Task.Factory.StarNew (...) or other Threading mechanisms.

My question is not to solve this very problem that I described, but I would like to hear from you about NHibenrate, Spring.NET and parallel approaches.

Thank you very much max

+6
nhibernate task-parallel-library
source share
3 answers

In NH, this is ISession, which is not thread safe, but ISessionFactory is completely thread safe, it easily supports what seems to you after. If you have developed session lifecycle management (and its dependent stores) so that you accept one single consecutive ISession through calls, then yes, you will have this problem. But if you designed your session processing template to accept only one ISessionFactory and not make assumptions about ISession, then there is nothing inherently to prevent you from interacting with NH in parallel.

Although you are not specifying a specific use case for the Internet, it is important to note that in web-oriented use cases (for example, which is a fairly common case for Spring.NET users, like many other NH management structures), the commonly used "Session" template The "Per-Request" of the ISession control (often referred to in Spring.NET as "Open Session In View" or simply "OSIV") will NOT and you will need to switch to a different ISession life cycle. This is because (as the name suggests) the session-per-request / OSIV template makes the assumption (currently incorrect in your case) that there is only one ISession instance on each HttpRequest (and, presumably, you want making these concurrent NH calls in the context of a single HttpRequest when using a network).

Obviously, in a non-web-based case where there is rarely a similar concept for a per-request session, you would hardly be faced with this problem, since session life-cycle management is rarely fine-grained / short-lived, as it is in web applications.

Hope this helps.

-Steve B.

+8
source share

This is the difficult thing you are asking for. DTC should be taken with caution.

The only solution I can know is to use reliable transactional messages (e.g. MSMQ + NServiceBus / MassTransit).

This design allows you to do this. It will look like this:

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

Then you can use two event handlers (Reactors) that handle the event and send EMail or create requests.

This will not allow you to share the transaction, but will ensure that the reactors start up (in a new transaction) when client creation is complete. It also has nothing to do with TPL.

+2
source share

OK, thanks for answer. I know that "ISession, which is not thread safe, but ISessionFactory is completely thread safe." My problem in the code above, for example, is that the whole operation completes in one transaction. So this.CreateCustomerAndAdresses (params) in main stream # 1 will use, for example, ISession # 1 with transaction # 1. Calling the other three in parallel will create three more threads and three more sessions and transactions, which will lead to database timeouts in my case. My assumption is that transaction number 1 was not successful because it is waiting for the completion of three parallel tasks. But three parallel tasks are trying to read from the database while the transaction is still active, which leads to deadlocks / timeouts.

So, is there a way to tell other threads / sessions not to create a new transaction, but to use main transaction # 1?

I am using TxScopeTransactionManager from Spring.NET, which uses DTC (System.Transactions). I have googled that maybe System.Transactions.DependentTransaction might work, but has no idea how to integrate it into my Spring.NET transaction-driven script.

thanks

0
source share

All Articles