2017-10-02 4 views
1

複数のinformixデータベースを接続するためにNhibernateを使用する.NET MVC webapiがあります。リポジトリと作業パターンの単位を使用します。.NET Nhibernateセッションでメモリ使用量が増加する

問題は、マルチプルリクエストをmvc web apiに送信すると、サーバーのメモリが増え、iis mvcのWebサイトが停止する問題です。

これは、作業クラスの単位である:

public interface IUnitOfWorkNH: IDisposable 
{ 
    void BeginTransaction(); 
    void Commit(); 
} 

public class UnitOfWorkNH : IUnitOfWorkNH 
{ 
    private ISessionFactory _sessionFactory; 
    private ITransaction _transaction; 

    public ISession Session { get; private set; } 

    public UnitOfWorkNH(string connection) 
    { 
     string stringConnection = ConfigurationManager.AppSettings["NH_DSN"].ToString(); 
     if (!string.IsNullOrEmpty(connection)) 
     { 
      stringConnection = connection; 
     } 
     _sessionFactory = Fluently.Configure() 
      .Database(OdbcConfiguration.InformixODBC.ConnectionString(stringConnection) 
      .Driver<NHibernate.Driver.OdbcDriver>() 
      .Dialect<NHibernate.Dialect.InformixDialect>() 
      //.ShowSql() 
     ) 
      .Mappings(m => 
         m.FluentMappings 
          .AddFromAssemblyOf<clsCiaMap>()) 
      .ExposeConfiguration(cfg => new SchemaExport(cfg) 
              .Create(false, false)) 

      .BuildSessionFactory(); 

     Session = _sessionFactory.OpenSession(); 
    }   

    public void BeginTransaction() 
    { 
     _transaction = Session.BeginTransaction(); 
    } 

    public void Commit() 
    { 
     try 
     { 
      // commit transaction if there is one active 
      if (_transaction != null && _transaction.IsActive) 
       _transaction.Commit(); 
     } 
     catch 
     { 
      // rollback if there was an exception 
      if (_transaction != null && _transaction.IsActive) 
       _transaction.Rollback(); 

      throw; 
     } 
     finally 
     { 
      Session.Dispose(); 
     } 
    } 

    public void Rollback() 
    { 
     try 
     { 
      if (_transaction != null && _transaction.IsActive) 
       _transaction.Rollback(); 
     } 
     finally 
     { 
      Session.Dispose(); 
     } 
    } 

    public void Dispose() 
    { 
     if (this._transaction != null) 
     { 
      this._transaction.Dispose(); 
      this._transaction = null; 
     } 

     if (this.Session != null) 
     { 
      this.Session.Dispose(); 
      Session = null; 
     } 
     this._sessionFactory.Dispose(); 
     this._sessionFactory = null; 
    } 
} 

これはリポジトリクラスです:

public interface IRepository<T> where T : class 
{ 
    List<T> GetAll(); 
    T GetById(int id); 
    T GetById(string id); 
    T GetById(T id); 
    void Save(T entity); 
    void Delete(T entity); 
} 

public class RepositoryNH<T> : IRepository<T> where T : class 
{ 
    ISession _session; 


    public RepositoryNH(ISession session) 
    { 
     _session = session; 
    } 

    public ISession Session { get { return _session; } } 

    public List<T> GetAll() 
    { 
     return Session.QueryOver<T>().List().ToList(); 
    } 

    public T GetById(int id) 
    { 
     return _session.Get<T>(id); 
    } 

    public T GetById(string id) 
    { 
     return Session.Get<T>(id); 
    } 

    public T GetById(T id) 
    { 
     return _session.Get<T>(id); 
    } 

    public void Save(T entity) 
    { 
     Session.SaveOrUpdate(entity); 
     Session.Flush(); 
    } 

    public void Delete(T entity) 
    { 
     Session.Delete(entity); 
    } 
} 

私はこれらのクラスに誤りがある場合、私は助けを必要と知ってはいけません。

+1

作業単位はセッションにのみ関連していなければならず、Web要求ごとに1つのセッションを使用するのが一般的です。セッションファクトリは、アプリケーション全体で1つのインスタンスにする必要があります。 – Najera

+0

しかし、私は複数のデータベースを接続する必要はありません、どうすればいいですか? – DanielVorph

+0

データベースごとに1つのセッションファクトリを用意しています。 – Najera

答えて

0

UnitOfWorkNHクラスのコンストラクタに新しいSessionFactoryを作成しています。これは、一度に複数のセッションファクトリインスタンスが存在することを示します。これらのセッションファクトリのすべてのインスタンスがメモリにロードされ、決して破棄されないため、メモリ使用量が増加します。

また、ビルドセッションファクトリは高価なコールです。新しいセッションファクトリを繰り返し作成すると、パフォーマンスが悪くなります。

理想的には、セッションファクトリはシングルトンである必要があります。アプリケーションの起動時に(BuildSessionFactory()メソッドを呼び出して)ビルドする必要があります。次に、_sessionFactory.OpenSession()ステートメントを使用してISessionインスタンスを作成するために、セッションファクトリの同じインスタンスを使用する必要があります。

以下はいくつかの生コードです。 ではなく、シングルトンが役に立つかもしれません。私はまだシングルトンの代わりに使うことをお勧めします。

internal static class NHSessionFactory 
{ 
    static Configuration nhConfiguration; 
    static ISessionFactory nhSessionFactory; 
    const FlushMode defaultFlushMode = FlushMode.Commit; 

    internal static ISessionFactory SessionFactory 
    { 
     get { return nhSessionFactory; } 
    } 

    internal static void CreateSessionFactory() 
    { 
     CreateSessionFactory(null); 
    } 
    internal static void CreateSessionFactory(string configFilePath) 
    { 
     CreateSessionFactory(configFilePath, defaultFlushMode); 
    } 
    internal static void CreateSessionFactory(string configFilePath, FlushMode flushMode = defaultFlushMode) 
    { 
     if(nhSessionFactory != null) 
      throw new InvalidOperationNHFacadeException("SessionFactory is already created."); 

     nhConfiguration = new Configuration(); 
     try 
     { 
      if(string.IsNullOrEmpty(configFilePath)) 
       nhConfiguration.Configure(); 
      else 
       nhConfiguration.Configure(configFilePath); 

      nhConfiguration.SessionFactory().DefaultFlushMode(flushMode); 
     } 
     catch(Exception exception) 
     { 
      throw new NHFacadeException("Failed to configure session factory.", exception); 
     } 
     try 
     { 
      nhSessionFactory = nhConfiguration.BuildSessionFactory(); 
     } 
     catch(Exception exception) 
     { 
      throw new NHFacadeException("Failed to build session factory.", exception); 
     } 
    } 

    internal static void CloseSessionFactory() 
    { 
     if(nhSessionFactory != null) 
     { 
      if(nhSessionFactory.IsClosed == false) 
       nhSessionFactory.Close(); 
      nhSessionFactory.Dispose(); 
      nhSessionFactory = null; 
     } 

     if(nhConfiguration != null) 
      nhConfiguration = null; 
    } 
} 

上記のコードでは、CreateSessionFactory()メソッドが冗長な呼び出しを検証することに注意してください。アプリケーションの起動時にCreateSessionFactory()に電話し、アプリケーション終了時にCloseSessionFactory()に電話するだけです。

関連する問題