6

私たちのアプリケーション (NHibernate と ASP.NET MVC を使用) は、ストレス テストを行うと、多くの NHibernate トランザクション エラーをスローします。主なタイプは次のとおりです。

  1. トランザクションが接続されていないか、切断されました
  2. 行が別のトランザクションによって更新または削除された (または、保存されていない値のマッピングが正しくない)
  3. トランザクション (プロセス ID 177) は、別のプロセスとのロック リソースでデッドロックされ、デッドロックの犠牲者として選択されました。トランザクションを再実行します。

誰かが例外 1 の理由を特定するのを手伝ってくれますか? コード内の他の例外を処理する必要があることはわかっています。これらのエラーを効率的に処理するのに役立つリソースを教えてもらえますか?

Q. セッションとトランザクションはどのように管理しますか?

A. Autofacを使用しています。すべてのサーバー リクエストに対して、コンテナの有効期間スコープ内のセッションを持つ新しいリクエスト コンテナを作成します。セッションをアクティブ化すると、トランザクションが開始されます。リクエストが完了すると、トランザクションをコミットします。場合によっては、トランザクションが巨大になる可能性があります。簡単にするために、すべてのサーバー要求はトランザクションに含まれています。

4

3 に答える 3

1

このスレッドには説明があります: http://groups.google.com/group/nhusers/browse_thread/thread/7f5fb68a00829d13

要するに、データベースは何らかのエラーのためにトランザクションを自動的にロールバックする可能性があるため、後でトランザクションをロールバックしようとすると、すでにロールバックされており、ゾンビ状態になっています。最初に実際にロールバックをトリガーした例外ではなく、TransactionException しか表示されないため、これはロールバックの実際の理由を隠す傾向があります。

ログに記録して、根本的なエラーの原因を突き止めようとする以外に、できることはあまりないと思います。

于 2011-03-01T15:11:59.243 に答える
1

このスレッドを見てください: http://n2cms.codeplex.com/Thread/View.aspx?ThreadId=85016

基本的に、この例外の考えられる原因として次のように述べています。

2010-02-17 21:01:41,204 1 WARN NHibernate.Util.ADOExceptionReporter - System.Data.SqlClient.SqlException: データベース 'databasename' のトランザクション ログがいっぱいです。ログ内のスペースを再利用できない理由を調べるには、sys.databases の log_reuse_wait_desc 列を参照してください。

トランザクション ログのサイズは、トランザクション中に行われた作業量に比例するため、トランザクションの書き込み部分でコマンドを「処理」するコマンド ハンドラにトランザクションの境界を設定することを検討する必要があります。次に、session#X を使用して、変更したい状態をロードし、変更してコミットします。すべて #X の 1 つの作業単位として行います。

読み取り側に関して言えば、データを読み取る別の ISession#Y があるかもしれません。この ISession は、たとえば RepeatableRead または Futures 機能と同様のもの内で読み取りをバッチ処理するために使用でき、単にキャッシュから読み取ることができます (実際には松葉杖ではありますが)。このようにすると、そうでない「エラー」から回復するのに役立つ場合があります。ライブロック、デッドロック、ビクティム トランザクション。

リクエストごとにトランザクションを使用する場合の問題は、作業中に ISession が大量の簿記データを取得することです。これらはすべてトランザクションの一部です。したがって、データベースはデータ (ロール、列、テーブルなど) をトランザクションに参加しているとマークし、実際には一部ではない (DDD の意味ではなく、データベースの意味で) 待機グラフを「エンティティ」にまたがらせます。アプリケーションが実行したコマンドのトランザクション境界。

記録として (他の人はこれをグーグルで調べています)、Fabio はデータ層からの例外の処理を扱った記事を持っていました。彼のコードの一部を引用します。

public class MsSqlExceptionConverterExample : ISQLExceptionConverter
{
  public Exception Convert(AdoExceptionContextInfo exInfo)
  {
      var sqle = ADOExceptionHelper.ExtractDbException(exInfo.SqlException) as SqlException;
      if(sqle != null)
      {
          switch (sqle.Number)
          {
              case 547:
                  return new ConstraintViolationException(exInfo.Message,
                      sqle.InnerException, exInfo.Sql, null);
              case 208:
                  return new SQLGrammarException(exInfo.Message,
                      sqle.InnerException, exInfo.Sql);
              case 3960:
                  return new StaleObjectStateException(exInfo.EntityName, exInfo.EntityId);
          }
      }
      return SQLStateConverter.HandledNonSpecificException(exInfo.SqlException,
          exInfo.Message, exInfo.Sql);
  }
}
  • 547 は、制約競合の例外番号です。
  • 208 は、SQL 内の無効なオブジェクト名の例外番号です。
  • 3960 は、更新の競合により中止されたスナップショット分離トランザクションの例外番号です。

したがって、あなたが説明したような同時実行の問題が発生している場合; これらは ISession を無効にし、上記のように処理する必要があることを覚えておいてください。

あなたが探しているかもしれないものの一部は、読み取り側と書き込み側が分離されている CQRS です。これが役立つかもしれません: http://abdullin.com/cqrs/http://cqrsinfo.com

要約すると、問題は、トランザクションの処理方法に関連している可能性があります。また、実行select log_wait_reuse_desc from sys.databases where name='MyDBName'してみて、何が得られるかを確認してください。

于 2010-11-20T19:51:37.373 に答える
0

この投稿はしばらく前に修正されたと思いますが、スレッドセーフではないNHibernateISessionとのスレッド共有の問題があるようです。基本的に、1つのスレッドがトランザクションを開始し、別のスレッドがトランザクションを閉じようとして、あらゆる種類の混乱を引き起こしています。

于 2012-01-27T11:37:24.683 に答える