トランザクション
Overview
このガイドでは、Lambda MongoDB を使用して MongoDB でトランザクションを実行する方法を学習できます。 トランザクション を使用すると、トランザクションがコミットされた後にのみデータを更新する一連の書込み操作を実行できます。
トランザクションが失敗した場合、Larevel 統合の MongoDB 操作を管理する MongoDB PHP ライブラリは、変更が反映される前に MongoDB がトランザクション内で行われたすべての変更を破棄するようにします。 トランザクション内のすべての変更が適用または破棄されるようにするトランザクションのこのプロパティはアトミック性と 呼ばれます。
MongoDB は、単一のドキュメントに対して書込み操作を不可分的に実行します。 複数のドキュメントに対する書込み操作のアトミック性や操作に複数のドキュメントにまたがるデータの一貫性が必要な場合は、マルチドキュメントトランザクションで実行します。
MongoDB は、ドライバーで予期せぬエラーが発生した場合でも、トランザクション操作のデータが一貫して保たれることを保証しているため、マルチドキュメントトランザクションはACID に準拠しています。
MongoDB のトランザクションの詳細については、サーバー マニュアルのトランザクションを参照してください。
このガイドには、次のセクションが含まれています。
要件と制限事項
MongoDB でトランザクションを実行するには、次の MongoDB バージョンとトポロジーを使用する必要があります。
MongoDB バージョン4.0以降
レプリカセットの配置またはシャーディングされたクラスター
MongoDB Server と Lambda 統合には次の制限があります。
MongoDB バージョン4.2以前では、トランザクション内で実行される書込み操作は既存のコレクションで実行される必要があります。 MongoDB バージョン4.4以降では、トランザクションで書き込み操作を実行するときに、サーバーは必要に応じてコレクションを自動的に作成します。 この制限の詳細については、サーバー マニュアルの「トランザクション内でのコレクションとインデックスの作成 」を参照してください。
MongoDB はネストされたトランザクションをサポートしていません。 別のトランザクション内でトランザクションを開始しようとすると、拡張機能は
RuntimeException
を発生させます。 この制限の詳細については、サーバー マニュアルの「トランザクションとセッション 」を参照してください。Lambda MongoDB はデータベース テストの特権
Illuminate\Foundation\Testing\DatabaseTransactions
とIlluminate\Foundation\Testing\RefreshDatabase
をサポートしていません。 回避策として、Illuminate\Foundation\Testing\DatabaseMigrations
特権を持つ移行を作成し、テストごとにデータベースをリセットします。
コールバックでのトランザクションの実行
このセクションでは、コールバックでトランザクションを実行する方法を示します。
この方法でトランザクションを実行する場合、コールバック メソッド内のすべてのコードが 1 つのトランザクションとして実行されます。
次の例では、トランザクションは、 Account
モデルで表されるデータベースアカウントから別のアカウントに金額を転送する書込み操作で構成されています。
DB::transaction(function () { $transferAmount = 200; $sender = Account::where('number', 223344)->first(); $sender->balance -= $transferAmount; $sender->save(); $receiver = Account::where('number', 776655)->first(); $receiver->balance += $transferAmount; $receiver->save(); });
オプションで、次のコード例に示すように、2 番目のパラメーターとして、失敗したトランザクションを再試行するための最大回数を渡すことができます。
DB::transaction(function() { // transaction code }, attempts: 5, );
トランザクションの開始とコミット
このセクションでは、トランザクションを開始してコミットする方法を説明します。
この方法でトランザクションを開始し、コミットするには、 DB::beginTransaction()
メソッドを呼び出してトランザクションを開始します。 次に、 DB::commit()
メソッドを呼び出してトランザクションを終了します。これにより、トランザクション内で実行されたすべての更新が適用されます。
次の例では、1 番目のアカウントの残高が 2 番目のアカウントに移動され、その後、最初のアカウントが削除されています。
DB::beginTransaction(); $oldAccount = Account::where('number', 223344)->first(); $newAccount = Account::where('number', 776655)->first(); $newAccount->balance += $oldAccount->balance; $newAccount->save(); $oldAccount->delete(); DB::commit();
トランザクションのロールバック
このセクションでは、トランザクションをロールバックする方法を説明します。 ロールバックは、そのトランザクション内で実行されたすべての書込み (write) 操作を元に戻します。 これは、データがトランザクション前の状態に戻ることを意味します。
ロールバックを実行するには、トランザクションがコミットされる前にいつでもDB::rollback()
関数を呼び出します。
次の例では、トランザクションは、 Account
モデルで表される 1 つのアカウントから複数の他のアカウントに金額を転送する書込み操作で構成されています。 送信者アカウントの残高が不足している場合、トランザクションはロールバックされ、モデルは更新されません。
DB::beginTransaction(); $sender = Account::where('number', 223344)->first(); $receiverA = Account::where('number', 776655)->first(); $receiverB = Account::where('number', 990011)->first(); $amountA = 100; $amountB = 200; $sender->balance -= $amountA; $receiverA->balance += $amountA; $sender->balance -= $amountB; $receiverB->balance += $amountB; if ($sender->balance < 0) { // insufficient balance, roll back the transaction DB::rollback(); } else { DB::commit(); }