• NHibernate 帮助类(单例实际运用)


      在NHibernate中,ISessionFactory是线程安全的,对应一个数据库。它是生成ISession的工厂。而ISession是线程不安全的。

      创建一个ISessionFactory需要消耗比较多的资源。因此,我们只在程序初始化的时候创建一次,以后就一直使用这个ISessionFactory。

      而ISession的创建只消耗很少的资源。因此我们可以随意创建。

    一、原始单例模式封装的ISessionFactory

      因此,对于ISessionFactory,我们使用饿汉单例模式实现它。

      原始饿汉单例模式封装ISessionFactory实例:

    复制代码
          //密封类
            public sealed class NSession
            {
                //私有、静态、只读
                private static readonly ISessionFactory sessionFactory = new Configuration().Configure().BuildSessionFactory();
    
                //私有构造函数,防止new
                private NSession()
                {
    
                }
    
                public static ISessionFactory GetSessionFactory()
                {
                    return sessionFactory;
                }
            }
    复制代码

      OK,对于ISessionFactory,以上代码就能够保证,整个程序只有一个SessionFactory的实例了。

      虽然,上面的代码已经使用单例模式实现了SessionFactory只能保证只有一个实例。但是,实际上我们能够进一步封装,实现管理到ISession。因为在我们的程序当中,我们实际上使用的是ISession。而我们要得到ISession对象,每次都要在代码里调用

      ISession iSession = NSession.GetSessionFactory().OpenSession();

      这样的代码来获得ISession对象。我们何不干脆封装到ISession呢?

    二、利用HttpContext绑定ISession

      上面说到,我们实际上要用到的是ISession对象而不是ISessionFactory对象。所以,我们干脆封装到ISession,实现更简单的调用。

      我们,先来看看以下代码的问题:

    复制代码
        //密封类
        public sealed class NSession
        {
            //私有、静态、只读
            private static readonly ISessionFactory sessionFactory = new Configuration().Configure().BuildSessionFactory();
    
            //私有构造函数,防止new
            private NSession()
            {
    
            }
    
            //返回ISession
            public static ISession GetSession()
            {
                return sessionFactory.OpenSession();
            }
        }
    复制代码

      测试代码:

    复制代码
            public PersonModel GetPerson(int Id)
            {
                ISession iSession1 = NSession.GetSession();
                ISession iSession2 = NSession.GetSession();
                HttpContext.Current.Response.Write(object.ReferenceEquals(iSession1, iSession2));   //输出 False,这是两个ISession对象
                return iSession1.Get<PersonModel>(Id);
            }
    复制代码

      我们看到,假若我们想上面那种封装方法,只要调用了一次GetSession()方法,就会生成一个新的ISession对象,虽然这样ISession占用的资源不多,但总感觉有多少浪费,我们何不将ISession绑定到HttpContext中,实现对于一次Http请求,只创建一个ISession呢?

    复制代码
        //密封类
        public sealed class NSession
        {
            //私有、静态、只读
            private static readonly ISessionFactory sessionFactory = new Configuration().Configure().BuildSessionFactory();
    
            //私有构造函数,防止new
            private NSession()
            {
    
            }
    
            //获取ISession
            public static ISession GetSession()
            {
                HttpContext context = HttpContext.Current;
                ISession currentSession = context.Items["ISession"] as ISession;
                //如果对于本次请求的HttpContext里还没有ISession对象,才OpenSession(),同时存入HttpContext中,用于下次判断和Close()
                if (currentSession == null)
                {
                    currentSession = sessionFactory.OpenSession();
                    context.Items["ISession"] = currentSession;
                }
    
                return currentSession;
            }
    
            //关闭ISession
            public static void CloseSession()
            {
                HttpContext context = HttpContext.Current;
                ISession currentSession = context.Items["ISession"] as ISession;
                //如果对于本次请求还没有创建ISession对象,那就用不着关闭了
                if (currentSession != null)
                {
                    currentSession.Close();
                    context.Items.Remove("ISession");
                }
            }
    
            //关闭SessionFactory
            public static void CloseSessionFactory()
            {
                if (sessionFactory != null)
                {
                    sessionFactory.Close();
                }
            }
        }
    复制代码

      我们再来测试下:

    复制代码
            public PersonModel GetPerson(int Id)
            {
                ISession iSession1 = NSession.GetSession();
                ISession iSession2 = NSession.GetSession();
                HttpContext.Current.Response.Write(object.ReferenceEquals(iSession1, iSession2));   //输出 True,这是两个ISession对象
                return iSession1.Get<PersonModel>(Id);
            }
    复制代码

      这次是输出True了。说明,这两个是同一个对象。

      以上代码就实现了HttpContext与ISession对象挂钩,对于一次HttpContext只创建一个ISession。当请求响应完毕,HttpContext里面的ISession就自动释放掉了。对于在请求响应未完毕之前,该ISession都一直处于打开状态(例如渲染视图时),不影响操作。

      以上代码依赖于HttpContext,因此只适合于Web程序。

    三、非Web程序中封装ISession

      而对于在WinForm或控制台项目中,由于程序是跑在客户端上,一个客户端电脑,哪怕你Open好几百个ISession都没什么问题,只是要管理好ISessionFactory,因为ISessionFactory还是比较占用资源的。

      对于非Web程序中的NHibernate帮助类实现如下:

    复制代码
        public sealed class NSession
        {
         private static readonly ISessionFactory sessionFactory; static NSession() { sessionFactory = new Configuration().Configure().BuildSessionFactory(); } public static ISession GetSession() { return sessionFactory.OpenSession(); } public static void CloseSession(ISession currentSession) { if (currentSession != null) { currentSession.Close(); } } public static void CloseSessionFactory() { if (sessionFactory != null) { sessionFactory.Close(); } } }
    复制代码
     
     
     
    0
    0
     
    (请您对文章做出评价)
     
    « 上一篇:HttpContext请求上下文对象
    » 下一篇:物理数据库设计 - 限定列的有效值
  • 相关阅读:
    nyoj17单调递增最长子序列(dp)
    nyoj995硬币找零(dp完全背包)
    nyoj36最长公共子序列(dp)
    hdu2058 The sum problem(枚举~~等差数列求和公式)
    Oceanbase:ld升级导致的error adding symbols: DSO missing from command line
    c++基础
    笔试中常出现的虚函数问题
    背包问题-面试中的动态规划
    拼音魔法-华东师范大学程序设计竞赛-3256-EOJ
    滴滴新锐2017实习生面试经历
  • 原文地址:https://www.cnblogs.com/mingxuantongxue/p/4778179.html
Copyright © 2020-2023  润新知