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_old
とdata_new
を古い値と新しい値に設定するchange_complete
に設定false
- 作成したばかりのドキュメント
transaction_id
の ObjectId に設定しますtransaction
3:アップデートを実行します。影響を受ける各ドキュメントについて:
data_new
そのドキュメント内の影響を受けるフィールドを値に置き換えますchange_complete
に設定true
4:transaction
ドキュメントのstatus
to を設定しますtrue
(すべてのデータが正常に変更されたため)
5:トランザクションの影響を受ける各ドキュメントについて、クリーンアップを行います。
data_old
anddata_new
は不要になったため削除しますlock_status
に設定false
(ドキュメントのロックを解除)
6:transaction
手順 1 で設定したドキュメントを削除します (または、提案に従って、完了としてマークします)。
任意の時点で失敗した場合、すべてのデータをロールバックするか、トランザクションを続行できるように論理的に機能すると思います (何をしたいかによって異なります)。明らかに、すべてのロールバック/リカバリ/など。transaction
ドキュメントおよびその transaction_id を持つ他のコレクション内のドキュメントを使用して、データベースではなくアプリケーションによって実行されます。
このロジックに、見逃した、または見落とした明らかなエラーはありますか? より効率的な方法はありますか (たとえば、データベースからの書き込み/読み取りを減らすなど)?