0

NHibernate を使用してデータベースに非同期で保存するときに、競合状態の問題が発生しています。最初にデータベースへの挿入が非同期で行われ、一意の ID が自動生成されます。この挿入がメイン スレッドに戻る前に、データベースで生成された一意の ID を持つ現在永続化されたオブジェクトを使用して、オブジェクトが何らかの方法で更新されます。更新するオブジェクトにはまだ ID 値がないため、session.Update を呼び出すと更新が失敗します。SaveOrUpdate を呼び出すと、エンティティの id フィールドが unsaved-value プロパティと等しいため、明らかに Update ではなく挿入になります。このコードで状況がより明確になることを願っています。

Entity entity = new Entity()
//update some fields
entity.PropertyTwo = "new value";
//dataObject as the database auto-generated Id
//insert new row asynchronously in different thread
Entity entity.Id = dao.save(entity.Clone()).Id

//before the the entity is returned from the database, the entity might be updated
entity.Property = 'new value';
//entity might be sent without an Id since the first asynch call has not returned yet.
//update asynchronously in another thread
Object dataObject = dao.Update(entity); //fails because Id is not set yet

1 つの解決策は、保存する前にコードで一意の ID を生成することです。この場合、データベースではなく、アプリケーションが一意の ID の増分を管理します。これを処理する他の方法はありますか?

4

2 に答える 2

1

1つのNHibernateセッションで複数のスレッドを作成しているようです。NHibernateのセッションはスレッドセーフではありません。2つの同時スレッドで同じセッションにアクセスしないでください。新しいスレッドで別のセッションを作成してみて、問題が解決するかどうかを確認してください。

NHibernateのドキュメントセクション10.2を確認してください。

于 2009-11-24T05:07:09.820 に答える
0

updateを呼び出す前に、ある種の「挿入が完了するのを待つ」タイプのロジックを配置する必要があります。これは、標準のマルチスレッド非同期プログラミングです。

マルチスレッド環境では、同じオブジェクトに対してInsertとUpdateを同時に呼び出すことができます。基礎となるコードが次のように十分にスマートであることを確認する必要があります。

  1. 更新前に挿入を行う
  2. 挿入が完了するのを待ってから、更新を開始してください

これを行うには多くの異なる方法があり、それらのどれもが必ずしも他のものより優れているわけではありません。概念的には、取得、破棄、および待機できるロックが必要です。

また、この問題は実際にはNHibernateとは何の関係もありません。マルチスレッドプログラミングは非常に困難です。複雑さが制御不能になりやすいため、可能な限り複数のスレッドを避けるのが最善です。

于 2009-11-27T11:37:33.647 に答える