与会话NHibernate的线程安全 [英] NHibernate thread safety with session

查看:160
本文介绍了与会话NHibernate的线程安全的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直使用NHibernate有一段时间了,发现不时如果我试图同时放要求两页(或接近,我可以),它会偶尔错误。所以,我认为这是因为我的会话管理是不是线程安全的。

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. So I assumed that it was because my Session management was not thread safe.

我认为这是我的课,所以我试图用不同的方法,从这个博客帖子<一个href=\"http://pwigle.word$p$pss.com/2008/11/21/nhibernate-session-handling-in-aspnet-the-easy-way/\">http://pwigle.word$p$pss.com/2008/11/21/nhibernate-session-handling-in-aspnet-the-easy-way/不过,我仍然得到同样的问题。我得到实际的错误是:

I thought it was my class so I tried to use a different method from this blog post http://pwigle.wordpress.com/2008/11/21/nhibernate-session-handling-in-aspnet-the-easy-way/ however I still get the same issues. The actual error I am getting is:

Server Error in '/AvvioCMS' Application.
failed to lazily initialize a collection, no session or session was closed
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: NHibernate.LazyInitializationException: failed to lazily initialize a collection, no session or session was closed

如果不是这样,没有DataReader的是开放的,但是这是主要的罪魁祸首。

Either that or no datareader is open, but this is the main culprit.

我下面放置我的会话管理类,任何人都可以发现,为什么我可能有这些问题?

I've placed my session management class below, can anyone spot why I may be having these issues?

public interface IUnitOfWorkDataStore
{
    object this[string key] { get; set; }
}


    public static Configuration Init(IUnitOfWorkDataStore storage, Assembly[] assemblies)
    {
        if (storage == null)
            throw new Exception("storage mechanism was null but must be provided");

        Configuration cfg = ConfigureNHibernate(string.Empty);
        foreach (Assembly assembly in assemblies)
        {
            cfg.AddMappingsFromAssembly(assembly);
        }

        SessionFactory = cfg.BuildSessionFactory();
        ContextDataStore = storage;

        return cfg;
    }

    public static ISessionFactory SessionFactory { get; set; }
    public static ISession StoredSession
    {
        get
        {
            return (ISession)ContextDataStore[NHibernateSession.CDS_NHibernateSession];
        }
        set
        {
            ContextDataStore[NHibernateSession.CDS_NHibernateSession] = value;
        }
    }

    public const string CDS_NHibernateSession = "NHibernateSession";
    public const string CDS_IDbConnection = "IDbConnection";

    public static IUnitOfWorkDataStore ContextDataStore { get; set; }

    private static object locker = new object();
	public static ISession Current 
    {
		get 
        {
            ISession session = StoredSession;

            if (session == null) 
            {
                lock (locker)
                {
                    if (DBConnection != null)
                        session = SessionFactory.OpenSession(DBConnection);
                    else
                        session = SessionFactory.OpenSession();

                    StoredSession = session;
                }
			}

            return session;
		}
        set
        {
            StoredSession = value;
        }
	}

    public static IDbConnection DBConnection
    {
        get
        {
            return (IDbConnection)ContextDataStore[NHibernateSession.CDS_IDbConnection];
        }
        set
        {
            ContextDataStore[NHibernateSession.CDS_IDbConnection] = value;
        }
    }

}

和我使用的实际存储是这样的:

And the actual store I am using is this:

public class HttpContextDataStore : IUnitOfWorkDataStore
{
    public object this[string key]
    {
        get { return HttpContext.Current.Items[key]; }
        set { HttpContext.Current.Items[key] = value; }
    }
}

我初始化的SessionFactory上的Application_Start了:

I initialize the SessionFactory on Application_Start up with:

NHibernateSession.Init(new HttpContextDataStore(), new Assembly[] { 
                typeof(MappedClass).Assembly});

更新

大家好,谢谢你的建议,我已经尝试了一些不同的东西,试图简化code,但我仍然运行到同样的问题,我可能有一个想法,为什么。

Hi guys, thanks for your advice, I have tried a few different things to try and simplify the code but I am still running into the same issues and I may have an idea why.

我创建每个请求的会话,并在需要时,但在我的global.asax我处理上Application_EndRequest会议。但是我发现了Application_EndRequest正在烧制不止一次而我在调试在加载页面的末尾。我认为事件只假设在请求的最后火一次,但如果它不是和一些其他项目正在试图使用Session(这是错误抱怨)的任何奇怪的原因,可能是我的问题,并在会话仍然线程安全的它只是被布置的早期。

I create the session per request as and when it is needed but in my global.asax I am disposing of the session on Application_EndRequest. However I'm finding the Application_EndRequest is being fired more than once while I am in debug at the end of loading a page. I thought that the event is only suppose to fire once at the very end of the request but if it isn't and some other items are trying to use the Session (which is what the error is complaining about) for whatever weird reason that could be my problem and the Session is still thread safe it is just being disposed of to early.

任何人有什么想法?我做了谷歌,只见那VS开发服务器不会导致这样的问题,但我通过IIS运行它。

Anyone got any ideas? I did a google and saw that the VS development server does cause issues like that but I am running it through IIS.

推荐答案

虽然我还没有看到你的整个codeBase的或你想解决的问题,你是如何使用NHibernate进行反思可能是为了。从<一个href=\"http://www.hibernate.org/hib%5Fdocs/nhibernate/1.2/reference/en/html/transactions.html\">documentation:

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:

您应该遵守以下
  创建NHibernate的做法时,
  会议:

You should observe the following practices when creating NHibernate Sessions:


      
  • 从不创建多个并发
      的ISession或ITransaction每个实例
      数据库连接。

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

在创建时请格外小心
  每个数据库不止一个的Isession
  每笔交易。该ISession的本身
  跟踪更新,以制成装
  对象,所以不同的Isession可能
  看到过时的数据。

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.

总的Isession是的的线程安全的!从不
  访问相同的Isession两
  并发线程。一个ISession是
  通常只有一个的单单元的工作的!

这最后一位是最相关的(并且在多线程环境的情况下,重要的),我在说什么。一个ISession应一次小原子操作中使用,然后处理。此外从文档:

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:

这是ISessionFactory是
  贵到创建线程对象
  要让所有共享
  应用程序线程。一个ISession是
  价格低廉,是非线程对象
  应该被使用一次,对于单
  业务过程,然后丢弃。

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.

结合,而不是存储ISession的本身这两种观念,存储会话工厂自认为是大的对象。然后您可以使用像SessionManager.GetSession()作为包装来检索会话存储工厂和实例化一个会话,并将它用于一个操作。

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.

的问题也是在ASP.NET应用程序的上下文中不太明显。你静态的作用域对象的Isession,这意味着它在整个AppDomain中共享。如果两个不同的页面请求的AppDomain中的生命周期内创建并同时执行,你现在有两个页面(不同的线程)触摸同一的ISession是的的安全。

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.

编辑:

好吧,我能看到你试图去与此有关。这听起来像你想实现公开会议在View模式,并有一对夫妇不同的路线可以采取如下:

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:

如果添加另一个框架是不是一个问题,看看类似 Spring.NET 。它是模块化的,所以你不必使用整个事情,你可以只使用NHibernate的帮助模块。它支持视图模式打开的会话。这里文档(标题21.2.10。网络会话管理)。

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").

如果您愿意推出自己的,检查出由比尔·麦卡弗蒂此$ C $的CProject张贴:的NHibernate的最佳实践。接近年底,他描述了实现通过自定义IHttpModule的格局。我也看到了在互联网实施的格局没有IHttpModule的帖子,但可能是你一直在努力的东西。

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. :)

这篇关于与会话NHibernate的线程安全的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆