LoginSignup
1
0

More than 1 year has passed since last update.

Laravelのトランザクションに後処理を突っ込みすぎないで。。。

Posted at

タイトル通り、トランザクションに後処理を突っ込みすぎないで。。。

try,catchでエラー捕捉すればいいだけなのだが、こんなコードに出会った

        DB::beginTransaction();
        try {
          // 1.データ取得する
                    // 2.取得したデータで条件分岐処理
          // 3.保存処理
          // 4.成功時にメール送信処理
        } catch (Exception $e) {
            DB::rollBack();
                       // 5.失敗時にメール送信処理
        }
        DB::commit();

トランザクションの中で1~5の処理をする必要はないが、全てぶち込まれていた(笑)
少なくとも、1,4,5は間違いなく、トランザクションの外で行った方がいいだろう
そもそも、複数テーブルに安全に保存するためにトランザクションを使用しているので、端的に言えば、トランザクションの中は複数テーブルに保存する処理だけ記載すればいい(場合によりけり)
1,2はトランザクションの前にやれば良いだけなので、今回は、4,5にフォーカスを当てていく

でもトランザクションの成否ってどうやって求めんの?

4,5をトランザクション外へ出すには、トランザクションが成功したのか、失敗したのかを知らなければならない。
どうすりゃいいんだ。。。と思ったら、さすがLaravelさん
抜かりはなかった!

トランザクションメソッドを使用して、それを変数に入れてやる
トランザクションが成功した場合はreturnで値を返してあげれば、保存したインスタンスがそのまま帰る
下記の例で言うと、Userインスタンスが帰る

       $result = DB::transaction(function() use($user) {
           $user->save();
           return $user;
       });

では、失敗した時は?
Throwableクラスが帰ってきた!
となると、例外はcatchで捕捉できるので、最終的には下記の形に落ち着いた。

        try{
            $result = DB::transaction(function() use($user) {
                $user->save();
                return $user;
            });
        }catch(\Throwable $e){
            Log::error($e->getMessage());
            // 5.失敗時にメール送信処理
        }
                 // catchで早期returnすれば、わざわざif文で$userの存在をチェックする必要はないような・・・
        if ($user) {
          // 4.成功時にメール送信処理
        }

少し冗長かもしれないが、保存処理はトランザクションに任せて、トランザクション成功と失敗の処理はトランザクションの外に分離できた。
トランザクション内に余計な処理が紛れないので、可読性もよくなったと思う。

教訓

トランザクションを使うにも、本当にトランザクション内でやらなければいけないのか考えるべし!
多少、冗長でも可読性は大事!
トランザクションの成否が取得できるなら、データ保存後の処理はトランザクションの外に書こう!

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0