20

MongoDB は、その性質上、この種のトランザクションをサポートしておらず、おそらく今後もサポートしないことを認識しています。ただし、ある程度制限された方法でそれらを使用する必要があることがわかったので、次の解決策を考え出しました。これが最善の方法であり、改善できるかどうか疑問に思っています。 ? (アプリに実装する前に!)

明らかに、トランザクションはアプリケーション (私の場合は Python Web アプリ) を介して制御されます。このトランザクション (任意のコレクション内) の各ドキュメントに対して、次のフィールドが追加されます。

'lock_status': bool (true = locked, false = unlocked),
'data_old': dict (of any old values - current values really - that are being changed),
'data_new': dict (of values replacing the old (current) values - should be an identical list to data_old),
'change_complete': bool (true = the update to this specific document has occurred and was successful),
'transaction_id': ObjectId of the parent transaction

さらに、transaction進行中の各トランザクションを詳述するドキュメントを格納するコレクションがあります。それらは次のようになります。

{
    '_id': ObjectId,
    'date_added': datetime,
    'status': bool (true = all changes successful, false = in progress),
    'collections': array of collection names involved in the transaction
}

そして、これがプロセスのロジックです。中断された場合、または他の方法で失敗した場合に、適切にロールバックできるように機能することを願っています。

1:transactionドキュメントを設定する

2:このトランザクションの影響を受ける各ドキュメントについて:

  • lock_statusに設定true(ドキュメントが変更されないように「ロック」する)
  • data_olddata_newを古い値と新しい値に設定する
  • change_completeに設定false
  • 作成したばかりのドキュメントtransaction_idの ObjectId に設定しますtransaction

3:アップデートを実行します。影響を受ける各ドキュメントについて:

  • data_newそのドキュメント内の影響を受けるフィールドを値に置き換えます
  • change_completeに設定true

4:transactionドキュメントのstatusto を設定しますtrue(すべてのデータが正常に変更されたため)

5:トランザクションの影響を受ける各ドキュメントについて、クリーンアップを行います。

  • data_oldanddata_newは不要になったため削除します
  • lock_statusに設定false(ドキュメントのロックを解除)

6:transaction手順 1 で設定したドキュメントを削除します (または、提案に従って、完了としてマークします)。


任意の時点で失敗した場合、すべてのデータをロールバックするか、トランザクションを続行できるように論理的に機能すると思います (何をしたいかによって異なります)。明らかに、すべてのロールバック/リカバリ/など。transactionドキュメントおよびその transaction_id を持つ他のコレクション内のドキュメントを使用して、データベースではなくアプリケーションによって実行されます。

このロジックに、見逃した、または見落とした明らかなエラーはありますか? より効率的な方法はありますか (たとえば、データベースからの書き込み/読み取りを減らすなど)?

4

3 に答える 3

13

一般的な応答として、MongoDB でのマルチドキュメント コミットは 2 フェーズ コミットとして実行できます。これについては、マニュアルである程度詳しく説明されています (参照: http://docs.mongodb.org/manual/tutorial/perform-two-phase-コミット/ )。

マニュアルで提案されているパターンは、次のとおりです。

  • target documentsource documentvalueおよびstate (トランザクションの)transactionsを含む別のコレクションを設定します。
  • initialとして新しいトランザクション オブジェクトを作成します。state
  • 取引を開始し、に更新stateするpending
  • トランザクションを両方のドキュメント (ターゲット、ソース) に適用する
  • トランザクションの状態を次のように更新しますcommitted
  • find を使用して、ドキュメントがトランザクションの状態を反映しているかどうかを判断し、OK の場合はトランザクションの状態を次のように更新します。done

加えて:

  • 障害シナリオを手動で処理する必要があります (以下で説明するように何かが発生しませんでした)。
  • state基本的に名前の値を導入することにより、ロールバックを手動で実装する必要がありますcanceling

実装に関する特定の注意事項:

  • lock_status、 、 などのdata_oldフィールドをdata_newソース/ターゲット ドキュメントに追加することはお勧めしません。これらは、ドキュメント自体ではなく、トランザクションのプロパティである必要があります。
  • ターゲット/ソース ドキュメントの概念を一般化するには、s を使用できると思いますDBref: http://www.mongodb.org/display/DOCS/Database+References
  • トランザクション文書が終わったら削除するという考えは好きではありません。state を に設定doneすることは、後でデバッグして、実行されたトランザクションの種類を調べることができるため、より良いアイデアのように思えます。ディスク容量も不足しないと確信しています(これには解決策もあります)。
  • あなたのモデルでは、すべてが期待どおりに変更されたことをどのように保証しますか? どういうわけか変更を検査しますか?
于 2012-09-19T11:41:39.380 に答える