Laravel Eloquent ORMトランザクション


96

Eloquent ORMは非常に優れていますが、PDOと同じ方法でinnoDBを使用してMySQLトランザクションを設定する簡単な方法があるのか​​、またはこれを可能にするためにORMを拡張する必要があるのでしょうか。

回答:


165

あなたはこれを行うことができます:

DB::transaction(function() {
      //
});

クロージャー内のすべてがトランザクション内で実行されます。例外が発生すると、自動的にロールバックされます。


1
クロージャの中でクラスのクエリを呼び出すことができますか?うまくいきますか?
Rafael Soufraz、2015年

悲しいことに、独自の関連メソッドでレコードを保存しているさまざまなモデルのインスタンスを作成している場合、私にとってはうまくいきません。
Volatil3 2015

(エラーメッセージの生成などのために)トランザクション内で例外をキャッチした場合、ロールバックを発生させるには例外を再発行する必要がありますか?
alexw '19

3
良い答えですが、いくつかのことに気が付きました:1.「use DB」を追加する必要があります。これを行うには、たとえばモデルファイルの先頭で行います。2. JSとは異なり、明示的に渡さない限り、親スコープのローカル変数にアクセスできません。そのため、「use」構成を追加する必要があります... DB :: transaction(function()use($ user){... $ userを参照するもの...});
Polsonby 2016年

Discussed in more detail hereリンクが死んでいる。
tomloprod

100

無名関数が気に入らない場合:

try {
    DB::connection()->pdo->beginTransaction();
    // database queries here
    DB::connection()->pdo->commit();
} catch (\PDOException $e) {
    // Woopsy
    DB::connection()->pdo->rollBack();
}

更新:laravel 4の場合、pdoオブジェクトはもうパブリックではありません。

try {
    DB::beginTransaction();
    // database queries here
    DB::commit();
} catch (\PDOException $e) {
    // Woopsy
    DB::rollBack();
}

15
また、ショートカットメソッドを使用することができますDB::beginTransaction()DB::commit()DB::rollback()。それは少しクリーンになります。
Flori

2
@Floriの提案を使用するには更新してください。クリーナーです。また、新しい回答を上に移動すると、回答の混乱が少なくなります。2つ目の方法に戻る前に、最初の方法を使用しました。
凍るような驚異的な

Laravelの古いバージョンのために、あなたは必要な場合があります:DB::connection()->getPdo()->beginTransaction();
代わりに

私は個人的にはDB::transactionwithコールバックはもっと
すっきりして

33

Eloquentを使用する場合は、これも使用できます

これは私のプロジェクトのサンプルコードです

        /* 
         * Saving Question
         */
        $question = new Question;
        $questionCategory = new QuestionCategory;

        /*
         * Insert new record for question
         */
        $question->title = $title;
        $question->user_id = Auth::user()->user_id;
        $question->description = $description;
        $question->time_post = date('Y-m-d H:i:s');

        if(Input::has('expiredtime'))
            $question->expired_time = Input::get('expiredtime');

        $questionCategory->category_id = $category;
        $questionCategory->time_added = date('Y-m-d H:i:s');

        DB::transaction(function() use ($question, $questionCategory) {

            $question->save();

            /*
             * insert new record for question category
             */
            $questionCategory->question_id = $question->id;
            $questionCategory->save();
        });

question->idトランザクションコールバックでの式はゼロを返します。
Christos Papoulas

@ChristosPapoulasという意味ですか、トランザクションで自動インクリメントIDを取得できませんか?
hellojinjie

26

閉鎖を避けたい場合、ファサードを使用したい場合は、次のようにすれば、きれいに保つことができます。

try {
    \DB::beginTransaction();

    $user = \Auth::user();
    $user->fill($request->all());
    $user->push();

    \DB::commit();

} catch (Throwable $e) {
    \DB::rollback();
}

いずれかのステートメントが失敗した場合、コミットはヒットせず、トランザクションは処理されません。


いずれかのステートメントが失敗すると、後続のステートメントは実行されません。トランザクションを明示的にロールバックする必要があります。
Jason

1
@ジェイソン私は答えを更新しました。ほとんどの(すべての)データベースエンジンで、接続が終了したときに、コミットされていないトランザクションクエリがコミットされないかどうかについて、私は2つ考えていました。しかし、私はあなたが言っていることに同意し、おそらく明示するのが最善です
Chris

18

私はあなたが閉鎖ソリューションを探していないと確信しています、よりコンパクトなソリューションのためにこれを試してください

 try{
    DB::beginTransaction();

    /*
     * Your DB code
     * */

    DB::commit();
}catch(\Exception $e){
    DB::rollback();
}

10

何らかの理由でこの情報をどこにでも見つけるのは非常に難しいため、Eloquentトランザクションに関連する私の問題がこれを正確に変更していたため、ここに投稿することにしました。

読んだ後、これをスタックオーバーフローの回答を、データベーステーブルがInnoDBではなくMyISAMを使用していることに気付きました。

トランザクションがLaravel(または思われる他の場所)で機能するためには、テーブルがInnoDBを使用するように設定されている必要があります。

どうして?

MySQL トランザクションとアトミック操作のドキュメントの引用(ここ):

MySQLサーバー(バージョン3.23-maxおよびすべてのバージョン4.0以上)は、InnoDBおよびBDBトランザクションストレージエンジンでのトランザクションをサポートしています。InnoDBは、完全なACIDコンプライアンスを提供します。第14章「ストレージエンジン」を参照してください。トランザクションエラーの処理に関する標準SQLとのInnoDBの違いについては、セクション14.2.11「InnoDBエラー処理」を参照してください。

MySQLサーバーの他の非トランザクションストレージエンジン(MyISAMなど)は、「アトミック操作」と呼ばれるデータ整合性の異なるパラダイムに従います。トランザクションの観点から見ると、MyISAMテーブルは事実上常に自動コミット= 1モードで動作します。アトミック操作は、多くの場合、より高いパフォーマンスで同等の整合性を提供します。

MySQLサーバーは両方のパラダイムをサポートしているため、アトミック操作の速度とトランザクション機能の使用のどちらがアプリケーションに最適かを決定できます。この選択は、テーブルごとに行うことができます。


これはDMLに当てはまり、DDLには必ずしも当てはまりません。
Yevgeniy Afanasyev 2015年

4

例外が発生した場合、トランザクションは自動的にロールバックされます。

Laravel Basicトランザクションフォーマット

    try{
    DB::beginTransaction();

    /* 
    * SQL operation one 
    * SQL operation two
    ..................     
    ..................     
    * SQL operation n */


    DB::commit();
   /* Transaction successful. */
}catch(\Exception $e){       

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