C军

不玩博客了!

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
  496 随笔 :: 0 文章 :: 634 评论 :: 571万 阅读

  在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(); } } }
复制代码

 

posted on   逆心  阅读(1596)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· [AI/GPT/综述] AI Agent的设计模式综述
点击右上角即可分享
微信分享提示