2010-03-02 32 views
13

Tôi đã viết một lớp NHibernateSessionFactory có chứa một ISessionFactory Nhibernate tĩnh. Điều này được sử dụng để đảm bảo rằng chúng ta chỉ có một phiên làm việc của nhà máy, và lần đầu tiên OpenSession() được gọi là tôi tạo phiên làm việc SessionFactory - lần sau tôi sử dụng cùng một phiên và mở một phiên làm việc đó. Mã trông giống như sau:Đảm bảo NHibernate SessionFactory chỉ được tạo một lần

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

Bây giờ tôi gặp sự cố. Ứng dụng của tôi được chia giữa máy khách và máy chủ. Các công cụ Nhibernate là ở phía máy chủ. Khi khởi động, cả máy khách và máy chủ của tôi đều muốn truy cập cơ sở dữ liệu thông qua một số dịch vụ sẽ sử dụng NhibernateSessionFactory. Kết quả là một điều kiện chủng tộc cho dù _sessionFactory được tạo ra trước khi yêu cầu đến từ máy khách. Nếu nó không phải là nó sẽ thất bại ..

Tôi đoán tôi cần một số loại xếp hàng hoặc chờ cơ chế trong NhibernateSessionFactory, nhưng tôi không chắc chắn về những gì để làm. Bất cứ ai cũng có cùng một vấn đề trước đây? Giải pháp tốt nhất là gì?

Trả lời

17

sessionFactory phải là một singleton an toàn.

Một mẫu phổ biến trong Java là xây dựng sessionFactory trong trình khởi chạy tĩnh. Xem HibernateUtil. Bạn có thể làm tương tự trong C#.

patterns khác để triển khai singleton, bao gồm cả việc sử dụng các phần khóa hoặc đồng bộ. Đây là một biến thể nhỏ nên giải quyết vấn đề của bạn nếu tôi hiểu nó một cách chính xác.

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

Cảm ơn! Nghe có vẻ hợp lý. Tôi vừa thêm một giải pháp sử dụng Mutex. Nhưng tôi nên sử dụng khóa thay thế? – stiank81

+0

Nhưng nếu tôi cần nhiều kết nối cơ sở dữ liệu cùng một lúc thì sao? Hiện tại tôi không biết cách giải quyết khác này để tạo nhiều Nhà máy phiên ... – JustAMartin

+0

Làm thế nào để bạn thực hiện điều này trong bộ điều khiển? – Chazt3n

4

Tôi đã giải quyết vấn đề này bằng cách sử dụng Mutex khi tạo SessionFactory. Điều này có hợp lý không:

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

Dường như làm việc như một sự quyến rũ. Nhưng tôi nên sử dụng khóa thay thế?

+2

Hmm ... Có vẻ như "kiểm tra kép khóa", mà không phải là một thực hành được đề nghị để thực hiện singleton (xem trang này http: // www.yoda.arachsys.com/csharp/singleton.html). Ngoài ra, một khóa đồng bằng có thể được sử dụng thay vì một mutex. – ewernli

+0

Cảm ơn! Nghe có vẻ như tôi nên đi với khóa đồng bằng để thay thế. – stiank81

+0

Bạn không nên sử dụng khóa, ít nhất bạn nên sử dụng lớp Màn hình. http://msdn.microsoft.com/en-us/library/x090d6tf.aspx –

Các vấn đề liên quan