1

NServiceBusを使用してシステムを構築しており、DataLayerはLinq2SQLを使用しています。

システムは2つのサービスで構成されています。

Service1はNSBからメッセージを受信します。データベース内のTable1にクエリを実行し、Table1にレコードを挿入します。特定の条件が満たされると、新しいNSBメッセージが2番目のサービスに送信されます。

Service2は、Service1からメッセージを受信し、データベースに関連しないその他の作業を行うときに、Table1のレコードも更新します。Service2は長時間実行されるプロセスです。

私が抱えている問題は、Service2がTable1のレコードを更新した瞬間、テーブルがロックされていることです。Service2が処理をすべて完了するまで、ロックは有効になっているようです。つまり、データコンテキストが破棄された後、ロックが解放されません。

これにより、Service1のクエリがタイムアウトします。Service2が処理を完了すると、Service1は問題なく処理を再開します。

したがって、たとえばService1コードは次のようになります。

int x =0;
using (DataContext db = new DataContext())
{
  x = (from dp in db.Table1 select dp).Count(); // this line will timeout while service2 is processing

  Table1 t = new Table1();
  t.Data = "test";
  db.Table1.InsertOnSubmit(t);
  db.SubmitChanges();
}

if(x % 50 == 0)
  CallService2();

service2のコードは次のようになります。

using (DataContext db = new DataContext())
{
  Table1 t = db.Table1.Where(t => t.id == myId);
  t.Data = "updated";

  db.SubmitChanges();

}

// I would have expected the lock to have been released at this point, but this is not the case.

DoSomeLongRunningTasks();

// lock will be released once service2 exits

DatacontextがService2に配置されているときに、ロックが解放されない理由がわかりません。

私が呼んでいる問題を回避するために:

db.ExecuteCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED");

これは機能しますが、私はそれを使用することに満足していません。この問題をきちんと解決したい。

誰かが以前にこの種の問題を経験したことがあり、誰かがそれを解決する方法を知っていますか?データコンテキストが破棄された後、ロックが解放されないのはなぜですか?

前もって感謝します。

非常に長い投稿でごめんなさい。

編集:

配送などの現実の状況でこれを見ると、次のようになります。

service1は、クレートレコードをデータベースに追加します。特定の数またはクレートレコードが存在する場合、クレートはコンテナレコードに追加されます(コンテナレコードが存在しない場合は作成されます)。次に、出荷レコードを作成し、すべてのコンテナを閉じて、出荷レコードに割り当てます。

次に、service2を呼び出して出荷記録を処理します。service2への呼び出しはBus.Send呼び出しですが、サガの一部である可能性があります。service2は、割り当てられている船の各クレートレコードを更新します。その後、他のいくつかの出荷指示が処理されます。service2が処理している間、次の出荷のためにさらに多くのクレートを受け取ることができますが、現状では、service2が出荷の処理を完了するまで、それらをコンテナに割り当てることはできません。

4

1 に答える 1

4

この動作が見られる理由は、NServiceBus で使用されるデフォルトの分離レベル (TransactionScope と同じ) が Serializable であるためです。これにより、テーブル全体がロックされます。

やりたいことは、NServiceBus レベルで別の分離レベルを設定することです。

これを行うには、流暢な初期化 API を使用し、.MsmqTransport() の呼び出し後にメソッド .IsolationLevel(IsolationLevel.ReadCommitted) を呼び出すか、他の値を渡す必要があります。それよりも低くすることはお勧めしません(コミットされていないものを読むのが好きです)。

上記のシナリオでは、ハンドラーの途中で分離境界を破るのに十分満足しているように見えるので、トップレベルのフローを管理するためにサガを使用することを好み、これらすべてを 1 つのハンドラーに入れることはしません。

それが役立つことを願っています。

于 2010-04-23T18:10:18.080 に答える