2017-03-03 36 views
3

SQL ServerでNHibernateを使用しているC#でバックエンドを持つASP.Netアプリケーションがあります。SQL ServerでNHibernateタイムアウト

最近私は、Webの特定のページで長い間、いくつかのタスクを実行している間、フリーズし、タイムアウトが発生することに気付きました(NHibernate例外)。

は、タイムアウトの問題の後、私は、SQL Server Management Studioのに行くと私は同じデータベースにどのような状態のないプロセスの数十、すべてのようにありますかモニターで見ることができます:私が持っている

Processes in SQL Server monitor

どこからでもソリューションを検索しています。セッションを間違って廃棄しているかどうかはわかりません。

public static void DisposeSession() 
{ 
    FlushSession(true); // Method that does a commit if there is a transaction 
    ISession Session = CurrentSessionContext.Unbind(sessionFactory); 

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

編集1:私は現在、Webフォームを使用していますし、要求の間には、共有セッションがない

、セッションが正しく配置されている。ここでは、私がセッションを配置する方法です。

ウェブのさまざまな部分(新しい要求を実行する)から始めて、プロセスがイメージのように成長し始めて、ある時点でウェブページがランタイムエラーまたはタイムアウト。

この動作を制御するにはどうすればよいですか? リクエストごとに1つのプロセスを持つことができ、処理を終了するときにプロセスを終了することは可能ですか?

編集2:私が間違っていた

は、セッション管理は、右の最初の答えで提供される方法で行われます。プロセスはありますが、NHibernateによって正しく管理されています。

+2

他のコードが何をしても、*静的な* 'DisposeSession'がどこから* unsafely *にセッションを取得しているという事実は、あなたのデータアクセスコードに深刻な問題があることを意味します。 A *セッション*は接続と同じです。可能な限り短時間、 'using()'ブロックで使用するので、何があっても処理され閉じられます。あなたは*共有していません。例外が発生した場合、セッションはとにかく役に立たず、破棄する必要があります。あなたが共有しているものは*工場*です。 –

+0

つまり、この情報を手助けすることはできません。あなたのコードが接続を漏らしている、例外の場合にセッションがリークすることが保証されています。複数の要求が同じセッションを使用しようとするとブロックする*保証*問題はDisposeSessionではありません。あなたはそのようなメソッドを持っていてはいけません。 –

+0

@PanagiotisKanavosあなたは正しいです... "Application_BeginRequest"メソッドでセッションを作成して保存し、静的メソッドを使わずに "Application_EndRequest"でそれを削除することは可能です...可能で安全ですか? – rpfc

答えて

2

まず、CurrentSessionContextがリクエスト間でセッションを共有していないことを確認してください。

通常、この種のコンテキストは、セッションをHttpContext.Current.Itemsディクショナリに格納します。これは、他のHTTPリクエストと共有されないようにするための安全な場所です。
代わりにリクエスト間でセッションを共有すると、アプリケーションは大量の負荷がかかるとほとんどのユーザーに失敗します。
ThreadContextまたはCallContextを使用すると、「ASP.Netのスレッドの敏捷性」により、一部のHTTP要求がスレッドを切り替えて以前のThreadContextおよびCallContextを失うため、負荷のかかる要求によって定期的に失敗します。 HttpContext.Current.Itemsは、http要求がスレッドを切り替えるときには保証されます。

このCurrentSessionContextが正しいと思われる場合は、DisposeSessionを修正してください。フラッシュが失敗した場合にセッションが閉じられることを保証するものではありません。その後

public static void DisposeSession() 
{ 
    try  
    {  
     FlushSession(true); // Method that does a commit if there is a transaction 
    } 
    finally 
    { 
     ISession Session = CurrentSessionContext.Unbind(sessionFactory); 

     if (Session != null) 
     { 
      // Dispose closes the session too. And Close dispose the transaction 
      // if there was one. And transaction Dispose rollbacks if it was pending. 
      Session.Dispose(); 
     } 
    } 
} 

、常にあなたの要求が終了するどのような方法このDisposeSessionと呼ばれるチェック:

それはおそらくよりのようにする必要があります。特に例外をトリガするリクエストで何が起きているかを確認します。これにはResponse.Redirect("...")のようなThreadAbortExceptionで動作するリダイレクトのケースも含まれます。

セッション管理:私は通常使用してセッション管理パターンについて

は、私は、要求ごとのライフサイクルと、それは要求のどのような結果を配置されます保証するHTTPモジュールと、それは注射を依存関係にバインドアクションフィルタ(MVC)によって処理されるトランザクションを使用します。

あなたのパターンはそれとはかけ離れています。あなたがそれを変更したいなら、NHibernateへの古いタイマー寄稿者とNHibernateプロファイラの作者からのこのblog post seriesに続いて簡単にすることができます。

+0

あなたが書いたことは、Entity Frameworkでは保持されますが、* NHibernateではありません。EFのコンテキストとは異なり、セッションは慎重に扱わなければならないホットポテトです。例外とスレッドの安全が主な問題です。単一のデータベースエラーで、*新しい*セッションを作成する必要があります。古いものは役に立たない。これはセッションを挿入できないことを意味し、工場に注入する必要があります。 –

+0

私はEFやNHを扱うのか、セッションや文脈の失敗であろうと、私はいつもそれを破棄します(処分する)。私は例外の流れを許可し、私のエラーページはセッションを必要としないので、そのままの状態にしておきます。私が特定のケースで失敗後と同じリクエスト内でDBのやりとりを必要とする場合、その必要性を持つクラスはセッションファクトリへの依存性を保持し、その特定の必要性にのみ使用された新しいセッションを取得し、 (BtW、私は失敗したEFコンテキストを信頼することはないでしょう) –

+0

EFコンテキストは失敗しません。彼らは*例外安全です。例えば、デッドロックから復旧したい場合は、可能です。 NHでも、*工場にアクセスできない場合は、リクエストを再開する必要があります。 * factory *はセッションではなくDbContextに相当します。 –

関連する問題