14

我编写了一个 NHibernateSessionFactory 类,它包含一个静态 Nhibernate ISessionFactory。这用于确保我们只有一个会话工厂,并且第一次调用 OpenSession() 时,我创建了实际的 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 中的某种排队或等待机制,但我不确定该怎么做。以前有人遇到过同样的问题吗?最好的解决方案是什么?

4

2 回答 2

19

sessionFactory必须是线程安全的单例。

sessionFactoryJava 中的一个常见模式是在静态初始化程序中构建。请参阅HibernateUtil。您可以在 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();
}
于 2010-03-02T10:06:46.520 回答
4

我在创建 SessionFactory 时使用互斥锁解决了这个问题。这看起来合理吗:

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

似乎像魅力一样工作。但是我应该改用 lock 吗?

于 2010-03-02T10:07:32.617 回答