laravel: 複数のテーブルに対して一連のトランザクションを定義したい

rollback() するのめんどくさい人用

バージョン

laravel 6.18.15 で動作確認

概要

複数のテーブルに対し、原子性を守るためにトランザクションを適切に管理したい。

例えば、あるテーブルAと別のテーブルBがあるとして、
BはAの id カラムを外部キーとして登録することにするとき、
Aを save() してidを確定し、BにAのidをセットして save() ということをすると考えるが、
Bの登録時にDBスキーマ上の何らかの制約に引っ掛かり、save() に失敗するとする。

上記のような時、通常はAがDBに登録され、Bが登録されない。
このような中途半端な状態にすべきではないため、全ての save() が成功するまでコミットを抑制する。

もっとスマートにやりたいのだが現状これしかわからん

暫定

DBファサードの transaction() を利用する。

use Illuminate\Support\Facades\DB;

// モデルを作成し、リクエストから受け取った値を格納する
$a = new A;
$a->fill($request->all());
$b = new B;
$b->fill($request->all());

DB::transaction(function () use ($a, $b) {
    $a->save();

    // BにAのidを格納する
    $b->a_id = $a->id;
    $b->save();
});

transaction() 内で投げられた例外がキャッチされなかった場合、
引数に渡したクロージャの実行前までロールバックされる。