解決 Laravel 中 Event 與 Database Transaction 的問題

前言

說明 Laravel 中的 Event 與 Database Transaction 兩者同時運作時會遇到的問題,以及如何解決這些問題。

當 Event 與 Database Transaction 同時運作時會遇到的問題

使用 Laravel 進行開發時,Event 是常用的一個開發方式,主要的意思為當什麼事情(Event)發生的時候要做對應的事情(Listener),而當如果要處理的項目很多時有可能會影響執行速度, 所以可以透過 queue 的方式,讓他變成非同步的方式去進行。

但是如果遇到 Database transaction 的話, 執行的結果可能會不如預期,例如,使用者進行了資料更新,預計更新後會有一連串的動作要用更新後的資料進行處理,但可能 Event 在 Transaction commit 完成前先觸發執行,拿到了尚未完成更新的資料,進而導致錯誤發生。

如何解決

而在 Laravel 中,可以將對應 Listener 的 after_commit 設定為 true,表示該 Listener 會在 commit 後才執行,這樣就可以確認資料的正確性了

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

namespace App\Listeners;

use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;

class SendShipmentNotification implements ShouldQueue
{
use InteractsWithQueue;

public $afterCommit = true;
}

如果需要將這個功能設定調整為預設的話,可以直接到 config/queue.php 找到使用的 driver 的 connection 進行設定

1
2
3
4
5
'redis' => [
'driver' => 'redis',
// ...
'after_commit' => true,
],

Reference