最近在開發上碰到一個request要執行的任務比較多、後面的任務牽扯到第3方API因此有可能fail,此時前面執行的任務需要將資料回溯的問題。
另外還碰到race condition的資料庫資料同步問題:當兩個使用者同時按下某個按鈕時,資料庫的資料會出現問題。
前者需要利用資料庫的transaction功能確保任務全執行或是全不執行、後者需要用到lock/unlock將某些資料表鎖住不讓其他程序修改。
在Laravel中,該怎麼做呢?查了一下,大概整理出來。
Transaction
有兩種作法,第1種使用closure:
DB::transaction(function()
 {
      // do something
 });
第2種也許比較親切,
try {
    DB::connection()->getPdo()->beginTransaction();
    // database queries here
    DB::connection()->getPdo()->commit();
} catch (\PDOException $e) {
    // Woopsy
    DB::connection()->getPdo()->rollBack();
}
在Laravel facades的協助下,這兩種作法都滿簡潔有力的。
要注意的是,在第1種情況下,若是closure要使用到執行closure之前定義的變數,記得使用關鍵字「use」:
DB::transaction(function() use ($user_id)
{
    // do something with $user_id
});
Lock
要保證一次只有一個程序在修改某幾張資料表,以Mysql來說有LOCK跟UNLOCK可以用。Laravel並沒有直接支援此功能,不過這樣變通就可以了:
DB::connection()->getPdo()->exec( 'LOCK TABLES items WRITE, accounts WRITE, orders WRITE' ); // blah blah DB::connection()->getPdo()->exec( 'UNLOCK TABLES' );
這邊一次用WRTIE LOCK鎖住三張資料表。當然也有READ LOCK可以使用。
