NHibernate SessionFactory 线程安全问题

Posted

技术标签:

【中文标题】NHibernate SessionFactory 线程安全问题【英文标题】:NHibernate SessionFactory Thread safe Issue 【发布时间】:2011-11-13 15:59:04 【问题描述】:

所以这就是问题所在。我有一个通用类库,其中包含所有存储库、域和映射文件,因此可以在其他基于 Web 的应用程序中重用该库。现在在这个类库中有一段代码允许自己创建一个会话工厂以在其存储库中使用。代码看起来像这样。

        private static ISessionFactory sessionFactory;
        private static Configuration configuration;

        public static Configuration Configuration()
        
            if (configuration == null)
            
                configuration = new Configuration().Configure();
            
            return configuration;
        

        private static ISessionFactory SessionFactory
        
            get
            
                if (sessionFactory == null)
                
                    sessionFactory = Configuration().BuildSessionFactory();
                
                return sessionFactory;
            
        

        public static ISession GetCurrentSession()
        
            if (!CurrentSessionContext.HasBind(SessionFactory))
            
                CurrentSessionContext.Bind(SessionFactory.OpenSession());
            
            return SessionFactory.GetCurrentSession();
        

所以存储库调用 GetCurrentSession() 方法来获取 ISession。现在这工作正常,但我担心它可能不是线程安全的。任何人都可以帮助我用一种方法来帮助我使其线程安全。

注意事项:

我曾考虑在启动事件时在 web 应用程序的 global.asax 中配置和构建 SessionFactory,但问题在于,有问题的公共类库在 20 个不同的应用程序中使用,因此这意味着要使用所有应用程序和更新 global.asax 文件在我这样做之前我想把问题放在那里,看看是否还有其他方法可以解决这个问题。这样通用类库就可以自己配置它的 SessionFactory 并且是线程安全的。

感谢您阅读这个巨大的问题。将给予任何帮助。

【问题讨论】:

【参考方案1】:

会话工厂是线程安全的,会话不是。构建会话工厂需要受到保护:

    private static object lockObject = new object();

    private static ISessionFactory SessionFactory
    
        get
        
            lock (lockObject)
            
                if (sessionFactory == null)
                
                    sessionFactory = Configuration().BuildSessionFactory();
                
                return sessionFactory;
            
        
    

会话工厂是在线程第一次请求会话时创建的。这需要是线程安全的,以避免多次创建会话工厂。

通过会话工厂创建会话是线程安全的,因此您无需担心。

【讨论】:

感谢 Stefan。关于锁定上述代码的快速问题。锁确保每个线程都有自己的 SessionFactory 并且两个或多个 Session 工厂不是在同一个线程上创建的? 不,锁让第一个线程进来并创建静态会话工厂。第二个线程需要等到第一个线程离开锁定范围。当第二个进来时,会话工厂已经创建,它只是接受它。没有锁,会话工厂会被并行创建多次。 是的,因为 SessionFactory 属性也是静态的。修好了。【参考方案2】:

在 NHibernate 中,会话在设计上不是线程安全的。所以只要你有只有一个线程使用的会话应该没问题。 只要每个线程都有一个单独的 NHibernate 会话,您就可以为多个线程使用一个 NHibernate SessionFactory

欲了解更多信息,请查看以下链接:

https://forum.hibernate.org/viewtopic.php?p=2373236&sid=db537baa5a57e3968abdda5cceec2a24

【讨论】:

【参考方案3】:

我建议为每个请求使用一个会话,如下所示:

public ISession GetCurrentSession()

        HttpContext context = HttpContext.Current;

        var currentSession = context.Items["session"] as ISession;

        if( currentSession is null )
        
             currentSession = SessionFactory.GetCurrentSession()
             context.Items["session"] = currentSession;
        

        return currentSession;

【讨论】:

注意:除了上面的,我建议正确配置 NHibernate 的上下文会话 (nhibernate.info/doc/nhibernate-reference/…) 应该没有必要将会话粘贴在 HttpContext .Current(再次,顺便说一句,因为这是 NH 已经在 IIRC 内部所做的)。只需在需要时询问 SessionFactory.GetCurrentSession()。【参考方案4】:

根据 Stefan Steinegger 的评论,我认为在锁定之前添加一个空检查会更有效,这样如果 sessionFactory 已经初始化,则不需要每次都锁定。

private static object lockObject = new object();

private static ISessionFactory SessionFactory

    get
    
        if (sessionFactory != null)
        
            return sessionFactory;
        

        lock (lockObject)
        
            if (sessionFactory == null)
            
                sessionFactory = Configuration().BuildSessionFactory();
            
            return sessionFactory;
        
    

【讨论】:

以上是关于NHibernate SessionFactory 线程安全问题的主要内容,如果未能解决你的问题,请参考以下文章

NHibernate“无法确定 X 的类型”错误

如何使 nhibernate 不结合继承对象的结果?

Fluent 映射和 NHibernate Xml 配置

在使用fluent-nhibernate配置nhibernate时,为什么会出现MissingMethodException?

如何使这个线程安全

Linq Sum() 精度