在多线程Windows服务应用程序中使用NHibernate会话管理的最佳方法是什么?

13

我有一个多线程的Windows服务应用程序。我在该应用程序的数据访问层中使用了NHibernate。

对于此应用程序中的会话管理,您有什么建议?我读到了关于UNHAddins的内容,这是一个好的解决方案吗?

2个回答

17

我使用NHibernate内置的上下文会话(contextual sessions)。您可以在此处了解更多信息:

http://nhibernate.info/doc/nhibernate-reference/architecture.html#architecture-current-session

以下是我使用它的示例:

public class SessionFactory
{
    protected static ISessionFactory sessionFactory;
    private static ILog log = LogManager.GetLogger(typeof(SessionFactory));

    //Several functions omitted for brevity

    public static ISession GetCurrentSession()
    {
        if(!CurrentSessionContext.HasBind(GetSessionFactory()))
            CurrentSessionContext.Bind(GetSessionFactory().OpenSession());

        return GetSessionFactory().GetCurrentSession();
    }

    public static void DisposeCurrentSession()
    {
        ISession currentSession = CurrentSessionContext.Unbind(GetSessionFactory());

        currentSession.Close();
        currentSession.Dispose();
    }
}

另外,在我的Hibernate配置文件中,我还有以下内容:

<property name="current_session_context_class">thread_static</property>

4

我从未查看过 unhaddins,但这是我在处理 WCF 事务时使用的内容,应该也适用于多线程一般性问题。

这是会话上下文:

namespace Common.Infrastructure.WCF
{
    public class NHibernateWcfSessionContext : ICurrentSessionContext
    {
        private readonly ISessionFactoryImplementor factory;

        public NHibernateWcfSessionContext(ISessionFactoryImplementor factory)
        {
            this.factory = factory;
        }

        /// <summary>
        /// Retrieve the current session for the session factory.
        /// </summary>
        /// <returns></returns>
        public ISession CurrentSession()
        {
            Lazy<ISession> initializer;
            var currentSessionFactoryMap = OperationContext.Current.InstanceContext.Extensions.Find<NHibernateContextManager>().SessionFactoryMaps;
            if (currentSessionFactoryMap == null ||
                !currentSessionFactoryMap.TryGetValue(factory, out initializer))
            {
                return null;
            }
            return initializer.Value;
        }

        /// <summary>
        /// Bind a new sessionInitializer to the context of the sessionFactory.
        /// </summary>
        /// <param name="sessionInitializer"></param>
        /// <param name="sessionFactory"></param>
        public static void Bind(Lazy<ISession> sessionInitializer, ISessionFactory sessionFactory)
        {
            var map = OperationContext.Current.InstanceContext.Extensions.Find<NHibernateContextManager>().SessionFactoryMaps;;
            map[sessionFactory] = sessionInitializer;
        }

        /// <summary>
        /// Unbind the current session of the session factory.
        /// </summary>
        /// <param name="sessionFactory"></param>
        /// <returns></returns>
        public static ISession UnBind(ISessionFactory sessionFactory)
        {
            var map = OperationContext.Current.InstanceContext.Extensions.Find<NHibernateContextManager>().SessionFactoryMaps;
            var sessionInitializer = map[sessionFactory];
            map[sessionFactory] = null;
            if (sessionInitializer == null || !sessionInitializer.IsValueCreated) return null;
            return sessionInitializer.Value;
        }
    }
}

这是上下文管理器:

namespace Common.Infrastructure.WCF
{
    class NHibernateContextManager : IExtension<InstanceContext>
    {
        public IDictionary<ISessionFactory, Lazy<ISession>> SessionFactoryMaps = new Dictionary<ISessionFactory, Lazy<ISession>>();

        public void Attach(InstanceContext owner)
        {
            //We have been attached to the Current operation context from the ServiceInstanceProvider
        }

        public void Detach(InstanceContext owner)
        {
        }
    }
}

编辑:

为了明确,正如其他答案所述,线程静态上下文将可以直接使用。我提供的主要优点是1)您可以控制它,2)这是一种惰性实现,因此如果不必要,您无需为每个线程启动会话。在我看来,与数据库的连接越少越好。


我不确定我理解你的第二点。会话不是线程安全的,因此您必须为每个线程启动另一个会话。此外,NHibernate使用连接池,因此已经最小化了对数据库的打开连接。如果没有问题,就不要修复它,以我个人的看法。 - Cole W
同样针对WCF集成:如果您使用ThreadStatic会话上下文,它在开发时似乎可以工作,但是在生产中,当来自wcf管道的各个组件(例如:授权,身份验证)在不同的线程上执行时,您将遇到问题。- 根据此帖子:https://dev59.com/cVXTa4cB1Zd3GeqP13Zm#5393312 - lko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接