Laravelのトランザクションが何かと2通りの使い方

Laravelのトランザクションが何かと2通りの使い方

438 回閲覧されました

みなさんこんにちは、jonioです。

Laravelを使って1年以上経ちますがトランザクションが何かを知らなかったのでメモとしてこの記事を残します。

トランザクションとは

銀行で送金する例で考えます。

  • A君がB君に100万円送金した
  • B君は100万円入金された

ところがデータベースに何らかの不具合があって送金が失敗したらこうなります。

  • A君が100万円失う
  • B君は100万円入金されない

こういう失敗が起きないようにデータベースの処理をするのがトランザクションです。

図にすると下記になります。

実装方法を見ていきます、どっちの方法もコントローラーに記述します。

tryとcatchを使う方法

demoコントローラーがあったとして下記の記述をします。

<?php

  namespace App\Http\Controllers;

  use Illuminate\Http\Request;
  use App\Models\RoleType;

  //ここから追加
  use Illuminate\Support\Facades\DB;
  use Illuminate\Support\Facades\Log;
  //ここまで追加

  public function store(Request $request){
  
  
    //ここから追加
    try {
      DB::beginTransaction();
      YourModel::create([  
        "name" => $request->name,  
        "password" => $request->password,  
      ]);
      DB::commit();
    } catch (\Exception $e) {
      DB::rollback();
      
      
      //エラーを表示する為の記述
    }
    //ここまで追加
    
    
  }

9行目はトランザクションを使う為に記述して10行目はエラーをログに追加(あとで説明)するのに使います。

18行目はトランザクションを開始しています。

19行目〜22行目はテーブルに値を登録する時の方法と同じです、19行目の「YourModel」は適用したいモデル名を記載します。

「try」はテーブルに情報を追加する時に問題がない場合で「catch」はテーブルに情報を追加するのに問題があった場合です。

問題がなかったら23行目でテーブル情報を変更して問題がある場合は25行目で変更をなかったことにします。

そして25行目の下の行にエラーになった時の記述をします。

例えば「Log::error($e);」と書くと(これができるようにする為に10行目があります)エラーログが「Laravelのプロジェクト > storage > logs > laravel.log」に追加されていきます。

これがtryとcatchでやる方法です。

transactionメソッドを使う方法

コードは下記になります。

<?php

  namespace App\Http\Controllers;

  use Illuminate\Http\Request;
  use App\Models\YourModel;

  //ここから追加
  use Illuminate\Support\Facades\DB;
  //ここまで追加

  public function store(Request $request){
  
  
    //ここから追加
    DB::transaction(function () use ($request) {
      YourModel::create([  
        "name" => $request->name,  
        "password" => $request->password,  
      ]);
    });
    //ここまで追加
    
    
  }

この書き方の方が記述量が少ないのでかなりスッキリしています。

transactionメソッドを使った書き方が推奨されているみたいです。

注意点

トランザクションはテーブルに登録する時の処理なのでテーブル関係以外の処理をトランザクションの中に記述してはいけません。

transactionメソッドの欠点と解消法

tryとcatchを使う方法はtry〜catchの外で参照ができます。

public function store(Request $request){
  try {
    DB::beginTransaction();
    $reference = YourModel::create([  
      "name" => $request->name,  
      "password" => $request->password,  
    ]);
    DB::commit();
  } catch (\Exception $e) {
    DB::rollback();
  }
  
  return view('user.show', compact('$reference'));
}

ところがtransactionメソッドを使うと参照ができません。

public function store(Request $request){
  DB::transaction(function () use ($request) {
    $reference = YourModel::create([  
      "name" => $request->name,  
      "password" => $request->password,  
    ]);
  });
  
  return view('user.show', compact('$reference'));   
}

ですが下記の書き方をすれば参照ができます。

public function store(Request $request){
  $reference = DB::transaction(function () use ($request) {     //この行に$referenceを記述する
    YourModel::create([  
      "name" => $request->name,  
      "password" => $request->password,  
    ]);
  });
  
  return view('user.show', compact('$reference'));   
}