一步步学习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);
}

从上面打印出的结果,我们可以看出通过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);
}
运行结果如下:

哦,天啊,怎么会出现异常呢?我们会发现异常信息是”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来绑定。
然后我们再次运行主程序来测试一下: 
没问题了,但是我们得到的这个ISession对象到底是不是同一个呢?我们再来测试一下,更改主程序代码:
static void Main(string[] args)
{
NHibernate.ISession session1 = DAL.NHibernateHelper.GetCurrentSession();
NHibernate.ISession session2 = DAL.NHibernateHelper.GetCurrentSession();
Console.WriteLine("两个Session是同一个吗?"+(session1 == session2));
}

很显然,两个ISession对象是同一个了!这样我们解决了上面我们提到的那个矛盾问题了。
在本章中,我们讨论了一下如何去管理ISession对象以及如何获得GetCurrentSession来获得同一个ISession对象,达到我们执行事务的目的。希望大家能够从本章中学到一点东西!但是老魏却是很认真的告诉大家,本章很重要哦!
一步步学习NHibernate(6)——ISession的管理的更多相关文章
- 一步步学习NHibernate(1)——NHibernate介绍
请注明转载地址:http://www.cnblogs.com/arhat 第十五章 从本章开始,老魏将给大家一起学习NHibernate这个流行的ORM框架,本来老魏想要和大家一起探讨微软的EF框架的 ...
- 一步步学习NHibernate(7)——HQL查询(1)
请注明转载地址:http://www.cnblogs.com/arhat 从本章开始,老魏带着大家来学习一下HQL语句.HQL语句NHibernate为我们提供的一种功能比较强大的查询语句,这个HQL ...
- 一步步学习NHibernate(5)——多对一,一对多,懒加载(2)
请注明转载地址:http://www.cnblogs.com/arhat 通过上一章的学习,我们建立了Student和Clazz之间的关联属性,并从Student(many)的一方查看了Clazz的信 ...
- 一步步学习NHibernate(4)——多对一,一对多,懒加载(1)
请注明转载地址:http://www.cnblogs.com/arhat 通过上一章的学习,我们学会如何使用NHibernate对数据的简单查询,删除,更新和插入,那么如果说仅仅是这样的话,那么NHi ...
- 一步步学习NHibernate(3)——NHibernate增删改查
请注明转载地址:http://www.cnblogs.com/arhat 在上一章中,我们配置了以下NHibernate的运行环境, 并介绍了NHibernate的中两个非常中重要的接口"I ...
- 一步步学习NHibernate(9)——连接查询和子查询(1)
请注明转载地址:http://www.cnblogs.com/arhat 在前几章中,我们把HQL的基本查询学习了一下,但是只有基本查询很显然不能满足我们的需求,那么就需要一下复杂查询比如" ...
- 一步步学习NHibernate(8)——HQL查询(2)
请注明转载地址:http://www.cnblogs.com/arhat 在上一章中,老魏带着大家学习了HQL语句,发现HQL语句还是非常不错的,尤其是在懒加载的时候,书写起来比较的舒服,但是这里老魏 ...
- 一步步学习NHibernate(2)——配置NHibernate的环境
请注明转载地址:http://www.cnblogs.com/arhat 第二章 环境搭建 在上一章中,我们知道了NHibernate是用来干什么的了,那么今天在本章中,我们开始搭建NHibernat ...
- 一步步学习NHibernate(10)——连接查询和子查询(2)
请注明转载地址:http://www.cnblogs.com/arhat 在上一章中,老魏讲述了HQL的链接查询,本章呢,老魏开始讲述HQL的子查询.子查询在SQL中也是占据着非常重要的作用,如果没有 ...
随机推荐
- Nodejs v4.x.0API文档学习(1)简介
文档参考地址:https://nodejs.org/dist/latest-v4.x/docs/api/ 简介 下面是用nodejs编写的一个web服务的例子,返回"Hello World& ...
- 使用Log4Net发送日志邮件 (转载)
前言 公司前几天重新确立了考核指标,主要是针对我们研发部,而我们的经理要求也高,对我们绩效考核扣分也挺狠的,100分的,出了几个严重bug就变 0分,反正只要被用户发现并且提出来了,就会扣分,没被用户 ...
- spark向量、矩阵类型
先来个普通的数组: scala> var arr=Array(1.0,2,3,4) arr: Array[Double] = Array(1.0, 2.0, 3.0, 4.0) 可以将它转换成一 ...
- spring3.2.0与mybatis3.2.7整合出错--Failed to read candidate component class--nested exception is java.lang.IllegalArgumentException
错误信息如下: org.springframework.beans.factory.BeanDefinitionStoreException: Failed to read candidate com ...
- Unity3d 播放高质量视频解决方案
Unity3d 播放高质量视频解决方案~ 最近在折腾一个视频游戏.真的是一个视频游戏,游戏主背景是个大视频.可能切换三四个视频,而且需要无缝切换. 平台是安卓,蕊片是rockclip.找了各式各样的插 ...
- Android更改桌面应用程序launcher的两种方式
http://blog.csdn.net/mdx20072419/article/details/9632779/ launcher,也就是android的桌面应用程序.下图是我正在使用的魅族手机的l ...
- php正则贪婪匹配与非贪婪匹配一些例子
http://www.111cn.net/phper/210/55600.htm 贪婪模式匹配的原则是: 在可匹配也可不匹配的情况下, 优先匹配,直到不能匹配成功的情况下,记录备选状态,并把匹配控制交 ...
- <转载>国外程序员推荐的免费编程书籍资源
一.George Stocker 提供了一大串,分类如下: How to Design Programs: An Introduction to Computing and Programming 2 ...
- ###再探Makefile
使用makefile.以前刚开始接触Makefile的时候,写过一个最简单的Makefile.点击查看Evernote原文. #@author: gr #@date: 2014-07-20 #@ema ...
- OC中 block 的用法
block 常用于反向传值 声明 返回值类型 (^block)(参数列表) 调用 闭包的名字=^(参数列表){}: 闭包的名字(): 如: void(^aaaaa)(int num,NSString ...