最近在開發上碰到一個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可以使用。