1

同時に4億スレッドで次のことを行う必要があります(おそらく2スレッドに近いですが、どちらの方法でも...):そのようなものが存在しない場合は、それを挿入します。

現在、アプリケーションは次のように述べています。

select rows from the db
if row count == 0,
    do some stuff
    insert a row

これが2つの別々のスレッドで同時に実行される状況があります。このように、2つのスレッドは、どちらかのスレッドが行を挿入する前に、それぞれが既存の行をチェックする可能性があります(実際にはこれまでのところ毎回実行されます)。したがって、重複する行があります。これは悪いです。

私が考えることができるすべてのアルゴリズムは、何らかの形で不十分です。

たとえば、これを行う場合:

open tx
insert a row
select rows
if row count > 2, rollback
else commit

トランザクションがREAD_COMMITTED分離を使用する場合、1つのスレッドは別のスレッドの挿入された行を認識せず、重複する可能性があります。分離するとREAD_UNCOMMITTED、各スレッドは他のスレッドの行を見ることができ、両方がロールバックします。MERGE挿入してから選択する代わりにステートメントを使用すると(またはその逆)、同じ問題が発生すると思います。

上記のアルゴリズムを同時に実行したときに正確に1行が挿入されることを保証するために使用するアルゴリズムはありますか?FWIW、私はSpringでDB2、mybatis、およびxmlベースのtx管理を使用していますが、可能であれば他の何かから喜んで翻訳します。

私は並行性に関しては初心者なので、この質問で、あなたが知っている本や記事によって改善された無知が明らかになった場合は、共有してください。

編集:

上記の挿入ステートメントは、ユーザーが持っていない場合に、ユーザーに何かを怠惰に付与することです。この場合、一意性の制約が適切です。ただし、アプリの他の場所では適切ではありません。:(

わかりやすくするために、例をもう少し具体的にします。

4

4 に答える 4

4

一意性制約を作成し、ReadCommittedを使用します。そうすれば、2番目のスレッドがdupを挿入しようとすると、ロールバックされますが、最初の挿入は機能します。

于 2012-10-29T21:16:44.410 に答える
1

私たちが見つけた唯一の解決策は、シリアル化可能なトランザクションで「基準を満たすレコードが存在しない場合に挿入」コマンドを発行することでした。SQL自体は、特定の基準を満たすものが存在しない場合にレコードを挿入するものであれば何でもかまいません(たとえば、MERGEは機能します)。このシナリオでは、1つのスレッドが選択されたステートメントの基準を満たす行の存在を確認すると、txが完了するまで、他のスレッドはその基準を満たすものを挿入できません。パフォーマンスのために、マージ操作のためだけに新しいtxを開き、完了後すぐにコミットしました。

このソリューションをDB2とOracleでテストし、成功しました。

于 2012-12-16T18:08:07.470 に答える
0

試してみることをお勧めします

MERGE

SQLステートメント。単一のステートメントに存在しない行を挿入する機能があります。

于 2012-11-02T01:18:32.390 に答える
0

私たちは似たようなことをします。テーブルをロックしたくないので、楽観的同時実行性と一意性の制約を使用します。

  1. 並行性のためにあなたを燃やす最初の条件は、2つの別々のスレッドに同じものを2回挿入することです。他の人が言及している解決策は、スキーマに一意性の制約を含めることです。列がNULL可能である複合制約がある場合、これは注意が必要な場合があります。この怒り狂う議論を参照してください:http://bugs.mysql.com/bug.php ?id = 8173したがって、一意性の制約のために追加の列が必要になる場合があります。

  2. やけどを負う可能性のある2番目の条件は、データを更新する必要があることです(1つまたは何かの増分など)。この場合、行バージョン管理を使用したHibernateでサポートされている楽観的同時実行性を使用します。http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/transactions.html#transactions-optimisticを確認してください。mybatisに似たようなものがあるかどうかはわかりませんが、同じものを手動で書くことができます。スレッドに衝突がある場合、1つは失敗します。私たちにとっては、両方が成功する必要があるため、衝突が発生した場合、失敗したスレッドは操作を再試行します(データの再読み取り、再処理、および再書き込みによって)。この場合、イーサネットの動作(または他の衝突ベースのプロトコル/操作)と同様のことを行います。つまり、失敗した場合は、何らかの方法でバックオフして再試行します。

HTH。

于 2012-10-30T00:46:45.937 に答える