アプリで使用しているデータベースの整合性を保つために、トランザクションのデータベース関数があります。Laravelでは、現時点で2通りの方法があります。Laravelのバージョン12.32.0において、DB::afterRollBack
が登場して、どちらとも機能的に同等になりました。
トランザクション
トランザクションを簡単に説明すると、例えば以下のように複数のデータベース文を実行するとき、
DB::table('points')->insert(['member_id' => 1, 'point' => 1000]); DB::table('points')->insert(['member_id' => 1, 'point' => 2000]);
最初のデータベース文が成功して、2番目のデータベース文が何等かの理由で失敗したときに、成功したものだけを残すのでなく、両方と何も起こらなかった状態に戻す機能です。
つまり、この2つデータベース文をあたかも1つのデータベース文のように扱い、両方が成功するならコミットとし、失敗が起こるならロールバックします。上の例では、成功なら3000ポイント追加され失敗したならたとえ1つが成功しても0ポイントの追加となります。
DB::beginTransaction
トランザクションをLaravelで実行するには、以下のようにDB::beginTransaction
を使います。
DB::beginTransaction(); try { DB::table('points')->insert(['member_id' => 1, 'point' => 1000]); DB::table('points')->insert(['member_id' => 1, 'point' => 2000]); DB::commit(); echo "ポイント追加成功しました。"; } catch (\Exception $event) { DB::rollBack(); echo "ポイント追加に失敗しました。"; echo $event->getMessage(); // エラーを表示 }
トランザクションと対象となるデータベース文は、try,catch
に入れて、成功ならDB::commit
で変更を保存し、エラーがあるなら(例外が発生)、DB::rollback
ですべての変更を戻します。DB::endTransaction
というものはないのでブロックで囲まれてなく変な感じですが、問題はありません。DB::beginTransaction
をtry
の中の最初の文としても変わりません。
DB::transaction
先の例では、いちいちコミットとロールバック、それぞれDB::commit
とDB::rollback
を指定する必要がありますが、DB::transaction
を使い対象のデータベース文を以下のようにクロージャのなかに入れるなら、結構すっきりします。
DB::transaction(function () { DB::table('points')->insert(['member_id' => 1, 'point' => 1000]); DB::table('points')->insert(['member_id' => 1, 'point' => 2000]); })
以下のようにデータを変数で渡すことも可能です。
$data = [ ['member_id' => 1, 'point' => 1000], ['member_id' => 1, 'point' => 2000] ]; DB::transaction(function () use($data) { DB::table('points')->insert($data[0]); DB::table('points')->insert($data[1]); })
また、DB::beginTransaction
のように、コミットとロールバックの後に必要なプログラム文を追加も以下のように可能です。
$data = [ ['member_id' => 1, 'point' => 1000], ['member_id' => 1, 'point' => 2000] ]; DB::transaction(function () use($data) { DB::afterCommit(function() { echo "ポイント追加成功しました。"; }); DB::afterRollBack(function () { echo "ポイント追加に失敗しました。"; }); DB::table('points')->insert($data[0]); DB::table('points')->insert($data[1]); })
注意する必要があるのは、対象のデータベース文は、DB::afterCommit
とDB::afterRollBack
の後に必ず置くことです。
また、DB::afterRollBack
は、Laravelのバージョン12.32.0においての登場なので、それより前のバージョンでは使えません。
最後に、DB::beginTransaction
の例のようにエラーをキャッチしたいなら、同様にtry,catch
を使います。
$data = [ ['member_id' => 1, 'point' => 1000], ['member_id' => 1, 'point' => 2000] ]; try { DB::transaction(function () use($data) { DB::afterCommit(function() { echo "ポイント追加成功しました。"; }); DB::afterRollBack(function () { echo "ポイント追加に失敗しました。"; }); DB::table('points')->insert($data[0]); DB::table('points')->insert($data[1]); }); } catch (\Exception $event) { echo $event->getMessage(); }メルマガ購読の申し込みはこちらから。