前提:
使用事務(wù)處理的話,需要數(shù)據(jù)庫(kù)引擎支持事務(wù)處理。比如 MySQL 的 MyISAM 不支持事務(wù)處理,需要使用 InnoDB 引擎。
事務(wù)操作
- 依據(jù) tp5.1手冊(cè)提供的 事務(wù)操作介紹,隨便寫(xiě)一個(gè)例子:
使用場(chǎng)景
Db::startTrans();
try{
Db::name('users')->insert(array('name'=>'mike','age'=>28));
Db::name('products')->where('id','=',1)->update(array('status'=>2));
Db::commit();
return json_return("事務(wù)操作成功"); // json_return() 為封裝返回json數(shù)據(jù)的方法
}catch (\Exception $e){
Db::rollback();
return json_return($e->getMessage()); // json_return() 為封裝返回json數(shù)據(jù)的方法
}
針對(duì)事務(wù)操作,我們首先需要了解事務(wù)的意義:這里不詳述了,不清楚的朋友可參考 MySQL事務(wù) 進(jìn)行了解。
常見(jiàn)問(wèn)題
-
問(wèn)題1:如上代碼中如果第一條新增語(yǔ)句 返回 true , 第二條更新語(yǔ)句返回 false ,那這個(gè)事務(wù)還是會(huì) commit 的,而不是我們預(yù)期的rellback,這是為什么?
如果想讓兩條 sql 真正按照自己的意愿都 "執(zhí)行成功(都返回 true 時(shí))" 時(shí)再提交事務(wù),那需要這樣寫(xiě): Db::startTrans(); try{ $res1 = Db::name('users')->insert(array('name'=>'mike','age'=>28)); $res2= Db::name('products')->where('id','=',1)->update(array('status'=>2)); }catch (\Exception $e){ Db::rollback(); } if($re1 && $re2){ Db::commit(); return json_return("事務(wù)操作成功"); // json_return() 為封裝返回json數(shù)據(jù)的方法 }else{ Db::rollback(); return json_return($e->getMessage()); // json_return() 為封裝返回json數(shù)據(jù)的方法 } 【延伸】 事務(wù)回滾的條件指的是 sql 語(yǔ)法報(bào)錯(cuò),而不是增加、刪除、更改 sql 時(shí)的影響行數(shù)為0 -
問(wèn)題2: 在事務(wù)中,使用了tp5 的函數(shù) $this->success(),即使事務(wù)里面的 sql 語(yǔ)句都成功了,但還是走了rollback,為什么?
Db::startTrans(); try{ Db::name('users')->insert(array('name'=>'mike','age'=>28)); Db::name('products')->where('id','=',1)->update(array('status'=>2)); Db::commit(); $this->success("事務(wù)操作成功"); }catch (\Exception $e){ Db::rollback(); $this->error($e->getMessage()); } 是因?yàn)?this->success() 這個(gè)函數(shù)的源碼其實(shí)也是會(huì)拋出異常(這里可查看$this->success() 的方法), 解決辦法: 將 catch (\Exception $exception) 改成 catch (\think\Exception\DbException $exception) // 僅catch sql 異常 即可。