簡單介紹 Laravel 的 DB Transactions

MySQL 資料庫,PHP 的好夥伴
在現在的版本中,MySQL 資料庫基本上都是使用 innoDB 作為預設的資料庫引擎
innoDB 與之前 MyISAM 相比,支援了 ACID 相容的交易(Transaction)功能

所謂的交易,是資料庫管理系統執行過程中的一個邏輯單位,由一個有限的資料庫操作序列構成

資料庫交易具備 ACID 性質,指的是

  • 原子性(Atomicity):交易作為一個整體被執行,包含在其中的對資料庫的操作要麼全部被執行,要麼都不執行
  • 一致性(Consistency):交易應確保資料庫的狀態從一個一致狀態轉變為另一個一致狀態。一致狀態的含義是資料庫中的資料應滿足完整性約束
  • 隔離性(Isolation):多個交易並行執行時,一個交易的執行不應影響其他交易的執行
  • 永續性(Durability):已被提交的交易對資料庫的修改應該永久儲存在資料庫中

簡單來說,資料庫需要處理從網站那裏傳來的上千、上萬甚至上百萬的交易
如果每筆交易會互相影響,或是說交易到一半停止,都會導致資料庫中的資料出現錯誤

在 Laravel 中,也有提供一個交易的功能

DB::transaction();

使用範例如下

use Illuminate\Support\Facades\DB;


// 如果下方的任一資料庫操作失敗,資料就會回滾(rollback)至操作前的狀態
DB::transaction(function () {
    DB::update('update users set votes = 1');

    DB::delete('delete from posts');
});

什麼時候會使用這樣功能呢?
舉例來說,以部落格文章為例,當我們寫好文章內容並設定好標籤,將新增文章請求發送至後端
後端會做兩件事情

  1. 新增一篇文章
  2. 更新文章與標籤的關聯表

這個時候我們就可以使用 transaction 功能確保這兩件事情都會執行或是都不執行
如果有任何一項操作執行失敗,資料庫就會回滾至執行前的資料狀態

// 新增文章
public function store(PostRequest $request, Post $post)
{
    $post->fill($request->validated());
    $post->user_id = auth()->id();

    // 將傳過來的 JSON 資料轉成 array
    $tagIdsArray = $this->tagsJsonToTagIdsArray($request->tags);

    DB::transaction(function () use ($post, $tagIdsArray) {
        // 新增文章
        $post->save();

        // 在關聯表新增關聯
        $post->tags()->attach($tagIdsArray);
    });

    return redirect()->to($post->link_with_slug)->with('success', '成功新增文章!');
}

 

參考資料
維基百科 - 資料庫交易
維基百科 - InnoDB
Laravel Document - Database Transactions

sharkHead 後端工程師,稍微擅長 Laravel、Python 與 Google
對於前端有興趣,無奈沒什麼慧根