一步步学习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中也是占据着非常重要的作用,如果没有 ...
随机推荐
- VIM 分割窗口
VIM 分割窗口 *08.1* 分割窗口 打开新窗口最简单的命令如下: :split 这个命令把屏幕分解成两个窗口并把光标置于上面的窗口中: +----------------------- ...
- 转--xcode duplicate symbol问题
遇到引用库重复定义的问题,需要解决. 项目需要,同时引用ZBar和QQ授权登录SDK,由于二者均使用了Base64处理数据,XCode编译时报错: duplicate symbol _base64 ...
- Android_ProgressBar
xml文件: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns ...
- Ubuntu 16.04 - 64bit 访问Windows磁盘报错 he NTFS partition is in an unsafe state. Please resume and shutdown Windows fully (no hibernation ...
今天在打开某个磁盘时,突然报错,报错信息如下 原因:Windows 未正常关闭,导致系统误以为存在临时缓存文件 解决方法: http://www.linuxidc.com/Linux/2014-05/ ...
- 20160503-spring入门1
一.Spring是什么 Spring是一个开源的控制反转(Inversion of Control ,IoC)和面向切面(AOP)的容器框架.它的主要目得是简化企业开发. IOC 控制反转 publ ...
- Android richtext
在项目开发过程中经常会遇到很多需要显示不同样式的,不同风格的文本信息:对此可以使用多个TextView来分别设置自已想要的样式以满足需求,但是使用多个TextView的方式不太好:使用多个TextVi ...
- 异步请求---Get
前端 <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> &l ...
- 国外一些知名ASP.Net开源CMS系统
1.Ludico Ludico是C#编写的居于ASP.NET 2.0的Portal/CMS系统.它的模块化设计是你可以按照你希望的使用或开发网站功能.它里面有高级的用户管理,一个所见即所的(WYSIW ...
- SQLServer 2008数据库查看死锁、堵塞的SQL语句
--每秒死锁数量 SELECT * FROM sys.dm_os_performance_counters WHERE counter_name LIKE 'Number of Deadlocks ...
- eclipse下的tomcat内存设置大小
在eclipse中设置,居然可以了, 设置步骤如下: 1.点击eclipse上的debug图标旁边的下拉箭头 2.然后选择Run Configurations, 3.系统弹出设置tomcat配置页面, ...