Help us understand the problem. What is going on with this article?

Laravelでトランザクションをネストせずに新しいトランザクションを切る

毎度同じことをやろうと思った時にどうやればいいか忘れてしまうので備忘も兼ねて

はじめに

Laravelでは以下のコードのようにするとトランザクションをネストしてSAVEPOINTを作成するため、やんごとなき事情で新しいトランザクションを切りたいなーと思ってもうまくいきません。
(ID発番が連番ではない場合に別テーブルでID発番を管理しトランザクションを分けることでロックする時間を短くするとか)

    DB::beginTransaction();
    {
        DB::beginTransaction();
        Animal::create(['name' => 'ぺんぎんさん']);
        DB::commit();
    }
    DB::rollBack(); // ぺんぎんさんの挿入もロールバックされる!

SAVEPOINTってなんだ!って方は以下の記事が非常にわかりやすかったです。
●トランザクションのネストの使い方まとめた(初心者向け)
https://qiita.com/_natsu_no_yuki_/items/e1db2a132cbff740896d

実装方法

トランザクションを乱立させることはそう多くないと思うので、簡単にできる別コネクションを作成する方法を記載します。

準備

config/database.phpにデフォルトで利用している接続情報をまるっとコピーします。

database.php
        // 既存の接続情報
        'mysql' => [
            'driver' => 'mysql',
            'url' => env('DATABASE_URL'),
            'host' => env('DB_HOST', '127.0.0.1'),
            'port' => env('DB_PORT', '3306'),
            'database' => env('DB_DATABASE', 'forge'),
            'username' => env('DB_USERNAME', 'forge'),
            'password' => env('DB_PASSWORD', ''),
            'unix_socket' => env('DB_SOCKET', ''),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'prefix_indexes' => true,
            'strict' => true,
            'engine' => null,
            'options' => extension_loaded('pdo_mysql') ? array_filter([
                PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
            ]) : [],
        ],

        // ★mysqlの項目を丸コピした接続情報
        'mysql_2' => [
            'driver' => 'mysql',
            'url' => env('DATABASE_URL'),
            'host' => env('DB_HOST', '127.0.0.1'),
            'port' => env('DB_PORT', '3306'),
            'database' => env('DB_DATABASE', 'forge'),
            'username' => env('DB_USERNAME', 'forge'),
            'password' => env('DB_PASSWORD', ''),
            'unix_socket' => env('DB_SOCKET', ''),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'prefix_indexes' => true,
            'strict' => true,
            'engine' => null,
            'options' => extension_loaded('pdo_mysql') ? array_filter([
                PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
            ]) : [],
        ],

実装

新しいトランザクションを切りたい場合は、DBファサードのconnectionで追加した接続情報のキーを設定します。
Eloquentを利用する場合は、その中でModelのインスタンスを作成し、setConnectionで追加した接続情報のキーを設定します。

  • 手動トランザクションの場合
    // デフォルトのコネクションでトランザクションの開始
    DB::beginTransaction();
    {
        // 追加した接続情報をセットして、トランザクションの開始
        $mysql2 = \DB::connection('mysql_2');
        $mysql2->beginTransaction();

        // Modelのインスタンスを作成し、追加した接続情報をセットする
        $animal = new Animal();
        $animal->setConnection('mysql_2');
        $animal->create(['name' => 'ぺんぎんさん']);

        // mysql_2のコネクションをコミットする
        $mysql2->commit();
    }
    // デフォルトのコネクションをロールバックする
    DB::rollBack(); // ぺんぎんさんのデータもコミットされている!
  • トランザクションメソッドの場合
    DB::transaction(function () {
        DB::connection('mysql_2')->transaction(function () {
            $animal = new Animal();
            $animal->setConnection('mysql_2');
            $animal->create(['name' => 'ぺんぎんさん']);
        });
        throw new Exception(); // ぺんぎんさんのデータもコミットされている!
    });

おわりに

なんだかんだネストではなく、別トランザクションを切りたくなることはあるので、newTransactionとかできると嬉しいんだろうなというお気持ちでした。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした