加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

asp.net – NHibernate线程安全与会话

发布时间:2020-12-15 23:10:27 所属栏目:asp.Net 来源:网络整理
导读:我一直在使用NHibernate一段时间,并不时发现,如果我尝试同时请求两个页面(或尽可能接近),它将偶尔会出错.所以我认为这是因为我的会话管理不是线程安全的. 我以为这是我的课,所以我试图使用不同的方法从这个博客文章http://pwigle.wordpress.com/2008/11/21/n
我一直在使用NHibernate一段时间,并不时发现,如果我尝试同时请求两个页面(或尽可能接近),它将偶尔会出错.所以我认为这是因为我的会话管理不是线程安全的.

我以为这是我的课,所以我试图使用不同的方法从这个博客文章http://pwigle.wordpress.com/2008/11/21/nhibernate-session-handling-in-aspnet-the-easy-way/,但我仍然得到相同的问题.我得到的实际错误是:

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

无论是否打开数据库,但这是主要的祸根.

我把会话管理类放在下面,任何人都可以发现为什么我可能会遇到这些问题?

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;
        }
    }

}

我正在使用的实际商店是这样的:

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

我在Application_Start上初始化SessionFactory:

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

更新

嗨,嗨,谢谢你的建议,我尝试了一些不同的东西来尝试和简化代码,但我仍然遇到同样的问题,我可能有一个想法为什么.

我根据需要创建会话,但是在我的global.asax中,我正在处理Application_EndRequest上的会话.不过我发现Application_EndRequest在加载页面结束时正在调试中被多次触发.我认为这个事件只是在请求的最后一次启动,但是如果没有,而其他一些项目正试图使用??Session(这是什么错误的抱怨),无论什么奇怪的原因,可能是我的问题,会话仍然是线程安全,它只是被提前处理.

任何人有任何想法?我做了一个谷歌,看到VS开发服务器确实造成这样的问题,但是我通过IIS运行它.

解决方法

虽然我没有看到您的整个代码库或您想要解决的问题,但是您如何重新思考如何使用NHibernate可能是有序的.从 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!

最后一点是我所说的最相关(对于多线程环境而言很重要).一个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()作为包装器从会话存储中检索工厂,并实例化一个会话并将其用于一个操作.

在ASP.NET应用程序的上下文中,问题也不太明显.您正在静态地定义ISession对象,这意味着它在AppDomain之间共享.如果在AppDomain的生命周期内创建了两个不同的页面请求并且同时执行,那么现在有两个页面(不同的线程)触及相同的ISession,这是不安全的.

基本上,尽量不要尽可能长时间地进行会议,尽量摆脱困难,看看是否有更好的效果.

编辑:

好的,我可以看到你想要去哪里.听起来你正在尝试实现Open Session In View模式,并且可以使用几种不同的路线:

如果添加另一个框架不是一个问题,请查看像Spring.NET.这是模块化的,所以你不必使用整个事情,你可以使用NHibernate帮助模块.它支持视图模式下的开放会话.文件here(标题21.2.10.“网络会话管理”).

如果你宁愿自己滚动,请查看Bill McCafferty发布的这个代码项目:“NHibernate Best Practices”.最后,他描述了通过自定义IHttpModule实现模式.我也看过互联网上的帖子来实现没有IHttpModule的模式,但这可能是你一直在尝试的.

我通常的模式(也许你已经在这里跳过了)首先使用框架.它消除了许多头痛.如果它太慢或不符合我的需要,那么我尝试调整配置或定制它.只有在此之后,我才试图滚动自己,但是YMMV.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读