在NHibernate中,ISessionFactory是线程安全的,对应一个数据库。它是生成ISession的工厂。而ISession是线程不安全的。javascript
建立一个ISessionFactory须要消耗比较多的资源。所以,咱们只在程序初始化的时候建立一次,之后就一直使用这个ISessionFactory。html
而ISession的建立只消耗不多的资源。所以咱们能够随意建立。java
所以,对于ISessionFactory,咱们使用饿汉单例模式实现它。git
原始饿汉单例模式封装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呢?session
上面说到,咱们实际上要用到的是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程序。
而对于在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(); } } }