zoukankan      html  css  js  c++  java
  • 一步步学习NHibernate(6)——ISession的管理

    请注明转载地址:http://www.cnblogs.com/arhat

    今天老魏那个汗啊,我的ThinkPad的电源线不通电了,擦啊。明天还得掏银子买一个!心疼啊,原装的啊。不过话说回来,已经用了将近10年了,已经算是可以的的了。不过就是心疼啊!明天还得给我的Thinkpad找个小三,哎!

    通过前面两章的学习,我们知道了爱NHibernate中的核心技术就是懒加载,这个懒加载技术主要作用于有关系的表中,比如多对一,一对多。通过懒加载技术,我们可以很容易的获得关联的数据,但是懒加载却是有一个缺点的,我们拿前面的例子来说,如果现在我们要获得一个班级中所有的学生信息,当学生表中的数据不是很多的情况下,那么还不怎么影响效率的,如果是1000条,但是我们只需要其中的两条,那么NHiberante不会非常智能的加载出来,而是把1000条数据全部加载进来,很显然这不是我们想要的结果了。

    如何解决这问题呢,我们在后面的HQL中来解决这个问题,本章呢,主要和大家来讨论一下对NHibernate的ISession管理。由于在NHibernate中,ISessionFactory是一个重量级对象,不能用一次创建一次,而是要在整个应用程序中只创建一次,而ISession是一个轻量级的对象,但是确是线程不安全的,所以我们今天要讨论的问题就是如何来管理他们。

    首先我们来先分析一下原来写的NHibernateHelper.cs

    public static class NHibernateHelper
    
        {       
    
    private static ISessionFactory factory = null;
    
    static NHibernateHelper() 
    
            {
    
                factory = new Configuration().Configure().BuildSessionFactory();
    
            }
    
    public static ISession OpenSession() 
    
            {
    
    return factory.OpenSession();
    
            }      
    
        }
    
    }

    在这个类中,我们把ISessionFactory定义成一个私有的静态变量,由于ISessionFactory是一个重量级对象,那么我们不能每次都要创建,这样浪费我们系统的资源的。所以,我们把它定义为一个静态的变量(当然,也可以使用单态来写)。然后我们在静态构造函数中通过Configuration读取配置文件并创建ISessionFactory对象,那么当程序运行的时候在内存中只有一个ISessionFactory对象了。

    接着,我们写了一个静态的方法,这个方法用来得到一个ISession对象用来和数据库打交道。但是这里需要说明的是当每一次调用OpenSession这个方法的时候,ISessionFactory都会创建一个全新的ISession对象。当然提出这个问题并不是说这样不好,而是这样创建出来的ISession对象是无法控制业务逻辑中的事务的(下面将会提到)。首先我们来测试一下通过OpenSession创建出来的ISession对象是不是全新的。

    我们在主程序中写一个测试的方法:

    static void Main(string[] args)
    
            {
    
                NHibernate.ISession session1 = DAL.NHibernateHelper.OpenSession();
    
                NHibernate.ISession session2 = DAL.NHibernateHelper.OpenSession();
    
    Console.WriteLine(session1 == session2);
    
            }

    wps_clip_image-8526

    从上面打印出的结果,我们可以看出通过OpenSession来创建的ISession对象都是全新的。那么这样的话会产生一个非常严重的问题,就是上面老魏说的如果我们在一次业务逻辑中同时执行了多个数据库操作,而每一次都需要打开一个ISession,那么事务是无法控制这些操作的。尤其在Web开发中,我们很有可能在一次请求过程中,执行了多次数据库操作,而却只需要一个事务提交,那么OpensSession是无法达到我们的要求的。所以NHibenrate为我们提供了一个新的方法用来创建ISession,这个方法就是GetCurrentSession。通过这个方法创建的ISession的生命周期是在一个上下文中,也就是说这个方法创建的ISession和当前线程以及当前请求时绑定在一起的,只要线程和请求没有被释放,那么着整个执行期间都是用这一个ISession。那么很显然,GetCurrentSession正是我们需要的。

    那么如何使用这个GetCurrentSession呢?我们需要在应用程序的配置文件中进行一个配置说明,现在我们打开App.config文件,给session-factory添加一个属性节点,内容如下:
     

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

    如果我们在winform应用程序中,这属性的取值为”thread_static”,如果在web项目中,这个取值为“web”。只有我们设置了这个节点,那么我们才能使用这个方法。我们来更改一下NHibernateHelper这个方法。在提供一个方法用来获得GetCurrentSession得到的ISession对象。

    public static ISession GetCurrentSession() 
    
      {
    
    return factory.GetCurrentSession();
    
    }

    好,我们现在来测试一下这个方法,看看是否能过获得ISession对象。在出程序中,我们更改一下Main方法。

    static void Main(string[] args)
    
            {
    
    Console.WriteLine(DAL.NHibernateHelper.GetCurrentSession().IsOpen);
    
            }

    运行结果如下:

    wps_clip_image-661

    哦,天啊,怎么会出现异常呢?我们会发现异常信息是”No Session bound to the current context”。没有一个Session和当前上下文绑定。这一点是初学者经常犯的一个错误,我们已经配置了App.config的信息,那么怎么会获得不到呢?大家从上面的信息可以知道,我们只是配置了”要”和当前的线程绑定,但是只是“要”还没有真正的绑定。需要我们来手动的进行一个绑定信息。

    根据分析,我们来改写一下NHibernateHelper的方法,能够让我们的GetCurrentSession能够正确运行。

    private static void BindSession()
    
            {
    
    if (!CurrentSessionContext.HasBind(factory))
    
                {
    
    CurrentSessionContext.Bind(factory.OpenSession());
    
                }
    
            }
    
    public static ISession GetCurrentSession()
    
            {
    
                BindSession();
    
    return factory.GetCurrentSession();
    
            }

    在NHibernateHelper中,我们添加一个方法,就是用来把ISession对象和当前上下文(thread或者是web请求)进行绑定,此时我们在调用GetCurrentSession之前,首先执行一下BindSession来绑定。

    然后我们再次运行主程序来测试一下:
    wps_clip_image-18733

    没问题了,但是我们得到的这个ISession对象到底是不是同一个呢?我们再来测试一下,更改主程序代码:

    static void Main(string[] args)
    
            {
    
                NHibernate.ISession session1 = DAL.NHibernateHelper.GetCurrentSession();
    
                NHibernate.ISession session2 = DAL.NHibernateHelper.GetCurrentSession();
    
    Console.WriteLine("两个Session是同一个吗?"+(session1 == session2));
    
            }

    wps_clip_image-2764

    很显然,两个ISession对象是同一个了!这样我们解决了上面我们提到的那个矛盾问题了。

    在本章中,我们讨论了一下如何去管理ISession对象以及如何获得GetCurrentSession来获得同一个ISession对象,达到我们执行事务的目的。希望大家能够从本章中学到一点东西!但是老魏却是很认真的告诉大家,本章很重要哦!

  • 相关阅读:
    5.19 省选模拟赛 T1 小B的棋盘 双指针 性质
    5.15 省选模拟赛 容斥 生成函数 dp
    5.15 省选模拟赛 T1 点分治 FFT
    5.15 牛客挑战赛40 B 小V的序列 关于随机均摊分析 二进制
    luogu P4929 【模板】舞蹈链 DLX
    CF 878E Numbers on the blackboard 并查集 离线 贪心
    5.10 省选模拟赛 拍卖 博弈 dp
    5.12 省选模拟赛 T2 贪心 dp 搜索 差分
    5.10 省选模拟赛 tree 树形dp 逆元
    luogu P6088 [JSOI2015]字符串树 可持久化trie 线段树合并 树链剖分 trie树
  • 原文地址:https://www.cnblogs.com/arhat/p/3574181.html
Copyright © 2011-2022 走看看