在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(); } } }