ThinkPHP 事務操作
1. 前言
前面小節(jié)學習了如何對數(shù)據(jù)庫增刪改查操作,本小節(jié)介紹一下和事務相關(guān)的操作。
2. MySQL 事務介紹
事務其實就是同一組具有原子性的 SQL
操作,也可以說是一個獨立的工作單元。若同一組數(shù)據(jù)庫操作中有任何一條 SQL
語句由于崩潰或其它的原因不能執(zhí)行成功,則該組數(shù)據(jù)庫操作都不會執(zhí)行,事務內(nèi)的語句要么全部執(zhí)行成功,要么全部執(zhí)行失敗。
3. 事務相關(guān)的案例
例如在一個銀行轉(zhuǎn)賬業(yè)務中存在一筆轉(zhuǎn)賬,小明向小紅轉(zhuǎn)賬 100 元
,數(shù)據(jù)庫的操作邏輯主要分為三步,步驟如下:
- 第一步,查詢小明賬戶余額數(shù)據(jù),若大于
100元
就可以繼續(xù)轉(zhuǎn)賬步驟,否則轉(zhuǎn)賬失敗。 - 第二步,小明賬戶余額
減少100元
。 - 第三步,小紅賬戶余額
增加100元
。
上面的例子中的三個步驟屬于同一組數(shù)據(jù)庫操作,必須要在同一個事務中操作,任何一個步驟執(zhí)行失敗,則所有的數(shù)據(jù)操作需要回滾至操作數(shù)據(jù)庫之前的狀態(tài)。
4. 事務特性
4.1 原子性
同一個事務可以被視為同一個不可分割的最小操作單元,其中全部的數(shù)據(jù)庫操作要么全部都成功,要么全部都失敗回滾,不能只執(zhí)行其中某一部分,這就是事務的 原子性
。
4.2 一致性
同一個事務操作總是從一個一致性的狀態(tài)轉(zhuǎn)換到另一個一致性的狀態(tài),如前面小明向小紅轉(zhuǎn)賬業(yè)務中,即使步驟三執(zhí)行失敗也不會導致小明賬戶減少 100 元,而小紅賬戶還沒增加 100 元這種情況。
4.3 隔離性
對于某一個事務來說,其內(nèi)部一組數(shù)據(jù)庫操作沒有提交之前,其他的事務操作是對該事務操作是不可見的。MySQL
的四種隔離級別分別是 順序讀
、可重復讀
、讀提交
、讀未提交
。
4.4 持久性
若同一個事務中對數(shù)據(jù)庫的操作一旦被提交,那么它們對數(shù)據(jù)庫所做的數(shù)據(jù)修改會永久地保存到數(shù)據(jù)庫中,不會因為系統(tǒng)崩潰而丟失。
5. ThinkPHP 事務操作
這里以之前第 08
小節(jié)介紹的課程表(course)
、教師表(teacher)
創(chuàng)建教師和課表信息數(shù)據(jù)接口為例學習事務操作。
5.1 定義接口路由
在 route/study.php
路由文件中定義一個路由如下:
//插入數(shù)據(jù)事務操作
Route::post('transaction','app\controller\Study\TeacherController@transaction');
如下圖所示:
5.2 新建控制器
接下來在 app\controller\Study\
目錄中添加 TeacherController
控制器:
<?php
namespace app\controller\Study;
use app\BaseController;
class TeacherController extends BaseController
{
}
如下圖所示:
5.3 定義路由指向的方法
下面定義一下路由里面指向的 transaction()
方法,方法如下:
<?php
namespace app\controller\Study;
use app\BaseController;
use app\Models\Study\CourseModel;
use app\Models\Study\TeacherModel;
use think\Exception;
use think\facade\Db;
use think\Request;
class TeacherController extends BaseController
{
public function transaction(Request $request)
{
//啟動事務
Db::startTrans();
try {
$time = time();
//插入教師 A 信息
$teacherModel = new TeacherModel();
$teacherModel->name = $request->param("name", "");
$teacherModel->age = $request->param("age", 0, "intval");
$teacherModel->id_number = $request->param("id_number", "");
$teacherModel->created_at = $time;
$teacherModel->save();
//插入 A 教師課程相關(guān)相關(guān)信息
$courseModel = new CourseModel();
$courseModel->course_name = $request->param("course_name", "");
$courseModel->teacher_id = $teacherModel->id;//上面插入教師產(chǎn)生的 id
$courseModel->created_at = $time;
$courseModel->save();
//提交事務
Db::commit();
} catch (\Exception $exception) { //捕獲異常
//若出現(xiàn)異常錯誤則回滾事務
Db::rollback();
throw new Exception($exception->getMessage());//拋出錯誤異常
}
return json("請求成功");
}
}
如下圖所示:
Tips: 其中
$request
是依賴注入的請求對象,和之前的$this->request->param()
獲取參數(shù)本質(zhì)是一樣的,另外需要用到的類請記得use
一下,如use think\facade\Db
,若使用phpStorm
編輯器會自動補齊。
5.4 請求接口
如下圖所示,可以在 postman
請求上述定義好的接口,并且?guī)闲枰砑拥膮?shù)字段,字段名需要和上面接收的一致:
{
"name" : "愛因斯坦",
"age" : 55,
"id_number" : "42011720100512065X",
"course_name" : "廣義相對論"
}
請求如下圖所示:
教師表(teacher)
信息如下:
課程表(course)
信息如下:
5.5 查看 sql 日志信息
可以在 runtime/log
目錄對應的以日期命名的目錄中,找到新增的日志文件可以看到內(nèi)容如下圖:
6. 小結(jié)
本小節(jié)介紹了事務,事務其實就是同一組具有原子性的 SQL
操作,也可以說是一個獨立的工作單元,事務有四個特點,分別是 原子性
、一致性
、隔離性
、持久性
,然后通過定義一個教師和課程表插入接口來展示事務操作,如在實際業(yè)務中遇到類似的業(yè)務邏輯也可以按照本小節(jié)的方式操作。
Tips: 代碼倉庫:https://gitee.com/love-for-poetry/tp6