【Laravel】DBのトランザクション処理を実装する方法

こんにちは!CODE CLUB965のKです!

今回は、LaravelでDBのトランザクション処理を実装する方法について書こうと思います。

トランザクション処理はデータの整合性を担保するために必要なものになりますので、よく分からないという方はぜひ読んでください。

トランザクションとは?

トランザクションは、データベースをある一貫した状態から別の一貫した状態へ変更するアクションを1つに束ねたものです。(引用元:Wikipedia

これだと分かりづらいと思うので具体的な例で言うと、

例えば、ATMで考えてみましょう。

ATMに3万円預けようとした時、「3万円を預かる」という処理と「3万円を受付けて記帳する」という処理がありますよね。
トランザクションとは、この「3万円を預ける」処理と「3万円を受付けて記帳する」処理を2つで1つの処理(一連の処理)だとすることです。

もしこのトランザクションがないと、もし何かしらの理由で処理が途中で失敗したとき、「3万円を預かる」処理はされて、「3万円を受付けて記帳する」と言う処理がされなかった場合、3万円はATMに吸い込まれどこかに消えてしまいます。

こんなことが起きたら最悪ですよね。銀行の信用に関わります。
このようなことが起きないようにするためにトランザクションがあります。

トランザクションがあれば、途中で処理が失敗した場合でも、全ての処理はされなかったことになるので上記のようなことは起きません。

Laravelでトランザクションを実装する

Laravelでトランザクションを実装する方法は2つあります。

  1. DBファザードのtransactionメソッドを利用する
  2. DBファザードのbeginTransaction, rollBack, commit を利用する

2 の方法は手動でトランザクションを張る方法で、自分でトランザクションを開始する位置などを指定することができます。
2 の方法が必要ない時は、基本的に 1 の方法を使えば問題ないです。

1. DBファザードのtransactionメソッドを利用する

この方法は基本以下のような書き方をすれば実装できます。
DBファザードのtransactionメソッドにクロージャーを渡し、その中でDBの更新処理を行えばいいだけです。

DB::transaction(function () {
    // 更新処理
});

具体的な例を書くと、

DB::transaction(function () {
    User::create([
        'name'     => 'hoge',
        'email'    => 'test@sample.com',
        'password' => 'password'
    ]);
});

上記のように書くことで、クロージャの中の処理が終わるまでコミットされず、終わったらコミットされるようになります。

引数を使いたい場合は、下記のように書くといいです。

$name = 'hoge';
$email = 'test@sample.com';
$name = 'password';

DB::transaction(function () use($name, $email, $password) {
    User::create([
        'name'     => $name,
        'email'    => $email,
        'password' => $password
    ]);
});

DB::transactionを呼び出して処理をしているだけです。
引数で渡しているクロージャの中の処理が順に行われます。

エラーなどで処理が終わらなかった場合に、データベースにはインサートされず、ロールバックされます。

DBファザードのbeginTransaction, rollBack, commit を利用する

こちらの方法は、try、catchを用いて更新処理を行います。

DBファサードのbeginTransactionメソッドでトランザクションを開始して、commitメソッドでデータベースに反映します。
ロールバックする時は、rollBackメソッドを使います。

具体例は、以下の通りです。

try {
    DB::beginTransaction();

    User::create([
       'name'     => 'hoge1',
        'email'    => 'test1@sample.com',
        'password' => 'password1'
    ]);

    User::create([
        'name'     => 'hoge2',
        'email'    => 'test2@sample.com',
        'password' => 'password2'
    ]);

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

DB::beginTransaction でトランザクションを開始する位置を指定します。
DB::commit が呼ばれるまでは、データベースに反映されません。

途中でエラー(例外)が発生した場合も、rollBack()が呼び出されるのでデータベースには反映されません。

今回はシンプルな例ですが、普通は複数のインサート処理がある場合が多いので、様々な処理がある場合、commit()まで行かずに処理が止まるとrollBackされ、インサートしたデータは反映されずに処理が終わります。

最後に

今回はトランザクション処理を実装する方法を2つ紹介しました。

トランザクション処理を入れることでデータの整合性を担保することができるので、データの登録や更新処理をする時は、基本的にトランザクション処理をするようにしましょう!

それでは、また!

Follow me!