2010-03-02 76 views
13

我寫了一個NHibernateSessionFactory類,它包含一個靜態的Nhibernate ISessionFactory。這用於確保我們只有一個會話工廠,並且第一次調用OpenSession()時,我創建了實際的SessionFactory - 下次我使用它並在其上打開一個會話。代碼如下所示:確保NHibernate SessionFactory只創建一次

public class NhibernateSessionFactory : INhibernateSessionFactory 
{ 
    private static ISessionFactory _sessionFactory; 

    public ISession OpenSession() 
    { 
     if (_sessionFactory == null) 
     { 
      var cfg = Fluently.Configure(). 
       Database(SQLiteConfiguration.Standard.ShowSql().UsingFile("Foo.db")). 
       Mappings(m => m.FluentMappings.AddFromAssemblyOf<MappingsPersistenceModel>()); 
      _sessionFactory = cfg.BuildSessionFactory(); 
      BuildSchema(cfg); 
     } 
     return _sessionFactory.OpenSession(); 
    } 

    private static void BuildSchema(FluentConfiguration configuration) 
    { 
     var sessionSource = new SessionSource(configuration); 
     var session = sessionSource.CreateSession(); 
     sessionSource.BuildSchema(session);    
    } 
} 

現在我遇到了問題。我的應用程序分爲客戶端和服務器端。 Nhibernate的東西在服務器端。在啓動時,我的客戶端和服務器都希望通過一些使用NhibernateSessionFactory的服務來訪問數據庫。結果是在請求來自客戶端之前是否創建_sessionFactory的爭用條件。如果不是,它會失敗..

我想我需要在NhibernateSessionFactory某種排隊或等待機制,但我不知道該怎麼做。任何人都有過同樣的問題?什麼是最好的解決方案?

回答

17

sessionFactory必須是線程安全的單例。

Java中的一種常見模式是在靜態初始化器中構建sessionFactory。見HibernateUtil。你可以在C#中做同樣的事情。

還有其他patterns來實現單例,包括使用鎖定或同步部分。如果我正確地理解了這個問題,那麼應該解決你的問題。

static readonly object factorylock = new object(); 

public ISession OpenSession() 
{ 
    lock (factorylock) 
    { 
     if (_sessionFactory == null) 
     { 
      var cfg = Fluently.Configure(). 
       Database(SQLiteConfiguration.Standard.ShowSql().UsingFile("Foo.db")). 
       Mappings(m => m.FluentMappings.AddFromAssemblyOf<MappingsPersistenceModel>()); 
      _sessionFactory = cfg.BuildSessionFactory(); 
      BuildSchema(cfg); 
     } 
    } 
    return _sessionFactory.OpenSession(); 
} 
+0

謝謝!聽起來很合理。我剛剛使用Mutex添加了一個解決方案。但我應該用鎖而不是? – stiank81 2010-03-02 10:08:51

+0

但是如果我需要同時連接多個數據庫呢?目前我不知道其他解決方法,以創建多個會話工廠... – JustAMartin 2012-12-07 11:19:13

+0

你如何在控制器中實現這一點? – Chazt3n 2013-01-31 15:52:15

4

我在創建SessionFactory時使用Mutex解決了這個問題。這看起來是否合理:

public class NhibernateSessionFactory : INhibernateSessionFactory 
{ 
    private static ISessionFactory _sessionFactory; 
    private static Mutex _mutex = new Mutex(); // <-- Added 

    public ISession OpenSession() 
    { 
     if (_sessionFactory == null) 
     { 
      _mutex.WaitOne();    // <-- Added 
      if (_sessionFactory == null) // <-- Added 
      {        // <-- Added 
       var cfg = Fluently.Configure(). 
        Database(SQLiteConfiguration.Standard.ShowSql().UsingFile("Foo.db")). 
        Mappings(m => m.FluentMappings.AddFromAssemblyOf<MappingsPersistenceModel>()); 
       _sessionFactory = cfg.BuildSessionFactory(); 
       BuildSchema(cfg); 
      }        // <-- Added 
      _mutex.ReleaseMutex();   // <-- Added 

     } 
     return _sessionFactory.OpenSession(); 
    } 

    private static void BuildSchema(FluentConfiguration configuration) 
    { 
     var sessionSource = new SessionSource(configuration); 
     var session = sessionSource.CreateSession(); 
     sessionSource.BuildSchema(session);    
    } 
} 

似乎工作就像一個魅力。但是,我應該使用鎖嗎?

+2

嗯...看起來像「雙重檢查鎖定」,這不是推薦的做法來實現單身人士(見本頁http:// www.yoda.arachsys.com/csharp/singleton.html)。此外,可以使用普通鎖來代替互斥鎖。 – ewernli 2010-03-02 10:11:31

+0

謝謝!聽起來像我應該用普通的鎖來代替。 – stiank81 2010-03-02 10:21:42

+0

您不應該使用鎖,至少應該使用Monitor類。 http://msdn.microsoft.com/en-us/library/x090d6tf.aspx – 2013-01-23 16:25:51

相關問題