NHibernate thread safety with session

后端 未结 3 2081
有刺的猬
有刺的猬 2021-01-31 12:30

I\'ve been using NHibernate for a while now and have found from time to time that if I try to request two pages simultaniously (or as close as I can) it will occasionally error.

相关标签:
3条回答
  • 2021-01-31 12:39

    The problem ended up being that my library for inversion of control was not managing the objects being created in HTTP context correctly so I was getting references for objects that should of not been available to that context. This was using Ninject 1.0, once I updated to Ninject 2.0 (beta) the problem was resolved.

    0 讨论(0)
  • 2021-01-31 12:46

    While I haven't seen your entire codebase or the the problem you're trying to solve, a rethinking of how you are using NHibernate might be in order. From the documentation:

    You should observe the following practices when creating NHibernate Sessions:

    • Never create more than one concurrent ISession or ITransaction instance per database connection.

    • Be extremely careful when creating more than one ISession per database per transaction. The ISession itself keeps track of updates made to loaded objects, so a different ISession might see stale data.

    • The ISession is not threadsafe! Never access the same ISession in two concurrent threads. An ISession is usually only a single unit-of-work!

    That last bit is the most relevant (and important in the case of a multithreaded environment) to what I'm saying. An ISession should be used once for a small atomic operation and then disposed. Also from the documentation:

    An ISessionFactory is an expensive-to-create, threadsafe object intended to be shared by all application threads. An ISession is an inexpensive, non-threadsafe object that should be used once, for a single business process, and then discarded.

    Combining those two ideas, instead of storing the ISession itself, store the session factory since that is the "big" object. You can then employ something like SessionManager.GetSession() as a wrapper to retrieve the factory from the session store and instantiate a session and use it for one operation.

    The problem is also less obvious in the context of an ASP.NET application. You're statically scoping the ISession object which means it's shared across the AppDomain. If two different Page requests are created within that AppDomain's lifetime and are executed simultaneously, you now have two Pages (different threads) touching the same ISession which is not safe.

    Basically, instead of trying to keep a session around for as long as possible, try to get rid of them as soon as possible and see if you have better results.

    EDIT:

    Ok, I can see where you're trying to go with this. It sounds like you're trying to implement the Open Session In View pattern, and there a couple different routes you can take on that:

    If adding another framework is not an issue, look into something like Spring.NET. It's modular so you don't have to use the whole thing, you could just use the NHibernate helper module. It supports the open session in view pattern. Documentation here (heading 21.2.10. "Web Session Management").

    If you'd rather roll your own, check out this codeproject posting by Bill McCafferty: "NHibernate Best Practices". Towards the end he describes implementing the pattern through a custom IHttpModule. I've also seen posts around the Internet for implementing the pattern without an IHttpModule, but that might be what you've been trying.

    My usual pattern (and maybe you've already skipped ahead here) is use a framework first. It removes lots of headaches. If it's too slow or doesn't fit my needs then I try to tweak the configuration or customize it. Only after that do I try to roll my own, but YMMV. :)

    0 讨论(0)
  • 2021-01-31 12:59

    I can't be certain (as I'm a Java Hibernate guy) in NHibernate but in hibernate Session objects are not thread safe by design. You should open and close a session and never allow it out of the scope of the current thread.

    I'm sure that patterns such as 'Open session view' have been implemented in .Net somewhere.

    The other interesting issue is when you put a hibernate entity in the session. The problem here is that the session that it is attached to will be closed (or should be) on the request finishing. You have to reattach the entity to the new (hibernate) session if you wish to navigate any non loaded associations. This in it's self causes a new issue if two requests try to do this at the same time as something will blow up if you try to attach an entity to two sessions.

    Hope this helps. Gareth

    0 讨论(0)
提交回复
热议问题