Laravel:DB :: transaction()でtry…catchを使用する


85

私たちは皆DB::transaction()、複数の挿入クエリに使用します。そうすることで、それをそのtry...catch中に置くべきですか、それともそれを包むべきですか?try...catch何か問題が発生した場合にトランザクションが自動的に失敗する場合を含める必要がありますか?

try...catchトランザクションのラッピングのサンプル:

// try...catch
try {
    // Transaction
    $exception = DB::transaction(function() {

        // Do your SQL here

    });

    if(is_null($exception)) {
        return true;
    } else {
        throw new Exception;
    }

}
catch(Exception $e) {
    return false;
}

反対に、DB::transaction()ラッピングトライ...キャッチ:

// Transaction
$exception = DB::transaction(function() {
    // try...catch
    try {

        // Do your SQL here

    }
    catch(Exception $e) {
        return $e;
    }

});

return is_null($exception) ? true : false;

または単にtry ... catchを使用しないトランザクション

// Transaction only
$exception = DB::transaction(function() {

    // Do your SQL here

});

return is_null($exception) ? true : false;

回答:


186

コードを介してトランザクションを手動で「終了」する必要がある場合(例外を介して、または単にエラー状態をチェックする場合)、使用するのでDB::transaction()はなく、コードをDB::beginTransactionand DB::commit/ DB::rollback():でラップする必要があります。

DB::beginTransaction();

try {
    DB::insert(...);
    DB::insert(...);
    DB::insert(...);

    DB::commit();
    // all good
} catch (\Exception $e) {
    DB::rollback();
    // something went wrong
}

トランザクションドキュメントを参照してください。


もう一度見てみると、これが私が探していた答えです。:)
エンチャント2014

@ alexrussell-データベースは別のものを生成しません\Exceptionか?私はこのジェネリックでそれをキャプチャでき\Exceptionますか?それなら素晴らしいです!
Artur Mamedov 2016

違いは何だDB::beginTransaction()とはDB:transaction()
Hamed Kamrava 2016

2
簡単な質問:例外の後にロールバックを実行しない場合、または例外をキャッチしない場合はどうなりますか?スクリプトの終了後の自動ロールバック?
neoteknic 2016

2
@HengSopheakこの質問はLaravel4データベースに関するものだったので、私の答えが5.3では正しくなくなった可能性があります。適切なコミュニティサポートを得るために、Laravel5.3タグを使用して新しい質問をする価値があるかもしれません。
alexrussell 2016年

25

PHP7を使用している場合は、Throwable incatchを使用して、ユーザーの例外や致命的なエラーをキャッチします。

例えば:

DB::beginTransaction();

try {
    DB::insert(...);    
    DB::commit();
} catch (\Throwable $e) {
    DB::rollback();
    throw $e;
}

コードがPHP5とコンパートメント化可能でなければならない場合は、以下を使用ExceptionしてThrowableください。

DB::beginTransaction();

try {
    DB::insert(...);    
    DB::commit();
} catch (\Exception $e) {
    DB::rollback();
    throw $e;
} catch (\Throwable $e) {
    DB::rollback();
    throw $e;
}

DB :: beginTransaction()も\ Exceptionをスローする可能性があるという事実はどうですか?try / catchに含める必要がありますか?
Michael Pawlowsky 2018

4
トランザクションが開始されていない場合は、何もロールバックする必要はありません。さらに、catchブロックで開始されていないトランザクションをロールバックしようとするのは良くありません。したがって、ブロックのDB::beginTransaction()前が適切な場所ですtry
ニック

12

あなたは深い内部を見れば、私は,, laravel 5にするために使用私のコード例ここでは、のtry..catch上でトランザクションを包む、あるいはそれらを逆転できるDB:transaction()Illuminate\Database\Connectionあなたのような同じマニュアルトランザクションを書くこと。

Laravelトランザクション

public function transaction(Closure $callback)
    {
        $this->beginTransaction();

        try {
            $result = $callback($this);

            $this->commit();
        }

        catch (Exception $e) {
            $this->rollBack();

            throw $e;
        } catch (Throwable $e) {
            $this->rollBack();

            throw $e;
        }

        return $result;
    }

したがって、このようにコードを記述し、フラッシュを介してメッセージをフォームにスローバックしたり、別のページにリダイレクトしたりするなどの例外を処理できます。REMEMBER return insideクロージャはtransaction()redirect()->back()で返されるため、トランザクションを処理する変数で返されるため、返してもすぐにはリダイレクトされません。

ラップトランザクション

$result = DB::transaction(function () use ($request, $message) {
   try{

      // execute query 1
      // execute query 2
      // ..

      return redirect(route('account.article'));

   } catch (\Exception $e) {
       return redirect()->back()->withErrors(['error' => $e->getMessage()]);
    }
 });

// redirect the page
return $result;

次に、ブール変数をスローし、トランザクション関数の外部でリダイレクトを処理するか、トランザクションが失敗した理由を取得する必要がある場合は、$e->getMessage()内部から取得できます。catch(Exception $e){...}


try-catchブロックなしでトランザクションを使用しましたが、それもうまく機能しました
hamidreza samsami 2017

@hamidrezasamsamiはい、データベース自動の巻き戻って、しかし、いつかあなたは知っておく必要があるクエリは、すべての...成功するかしていない
Anggaアリウィジャヤ

7
「ラップトランザクション」の例は間違っています。すべての例外がトランザクションコールバック内でキャッチされたためにクエリの1つが失敗した場合でも、これは常にコミットされます。try / catchをDB :: transactionの外部に配置したいとします。
redmallard 2018

3

複雑なtry-catchブロックよりも単純な構文を使用して解決できると思うので、この質問に答えることにしました。Laravelのドキュメントはこのテーマについてかなり簡単です。

try-catchを使用する代わりに、次のDB::transaction(){...}ようなラッパーを使用できます。

// MyController.php
public function store(Request $request) {
    return DB::transaction(function() use ($request) {
        $user = User::create([
            'username' => $request->post('username')
        ]);

        // Add some sort of "log" record for the sake of transaction:
        $log = Log::create([
            'message' => 'User Foobar created'
        ]);

        // Lets add some custom validation that will prohibit the transaction:
        if($user->id > 1) {
            throw AnyException('Please rollback this transaction');
        }

        return response()->json(['message' => 'User saved!']);
    });
};

次に、ユーザーとログレコードが相互に存在しなければ存在できないことがわかります。

上記の実装に関する注意事項:

  • コールバック内で返すをreturn使用できるように、トランザクションを確認してくださいresponse()
  • throwトランザクションをロールバックする場合(またはEloquent内からのSQL例外のように、例外を自動的にスローするネストされた関数がある場合)は、必ず例外を確認してください。
  • idupdated_atcreated_atおよびその他のフィールドは、のために利用可能AFTERのCREATIONである$user(このトランザクションの持続時間)オブジェクト。トランザクションは、使用している作成ロジックのいずれかを介して実行されます。ただし、AnyExceptionがスローされると、レコード全体が破棄されます。これは、たとえば、の自動インクリメント列がid失敗したトランザクションでインクリメントされることを意味します。

Laravel5.8でテスト済み

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.