《PHP學習:Yii2中事務(wù)的使用實例代碼詳解》要點:
本文介紹了PHP學習:Yii2中事務(wù)的使用實例代碼詳解,希望對您有用。如果有疑問,可以聯(lián)系我們。
相關(guān)主題:YII框架
PHP實例前言
PHP實例一般我們做業(yè)務(wù)邏輯,都不會僅僅關(guān)聯(lián)一個數(shù)據(jù)表,所以,會面臨事務(wù)問題.
PHP實例數(shù)據(jù)庫事務(wù)(Database Transaction) ,是指作為單個邏輯工作單元執(zhí)行的一系列操作,要么完全地執(zhí)行,要么完全地不執(zhí)行. 事務(wù)處理可以確保除非事務(wù)性單元內(nèi)的所有操作都成功完成,否則不會永久更新面向數(shù)據(jù)的資源.通過將一組相關(guān)操作組合為一個要么全部成功要么全部失敗的單元,可以簡化錯誤恢復并使應用程序更加可靠.一個邏輯工作單元要成為事務(wù),必須滿足所謂的ACID(原子性、一致性、隔離性和持久性)屬性.事務(wù)是數(shù)據(jù)庫運行中的一個邏輯工作單位,由DBMS中的事務(wù)管理子系統(tǒng)負責事務(wù)的處理.
PHP實例準備
PHP實例數(shù)據(jù)庫引擎為innodb
PHP實例本文使用的yii版本為2.0.5,只要是2.0以上就沒有問題
PHP實例運行環(huán)境為PHP7.0.0,Mysql5.6
PHP實例Yii中的事務(wù)
PHP實例處理異常
PHP實例
/**
* 測試事務(wù)
*/
public function actionTest(){
//創(chuàng)建事務(wù)
$tr = Yii::$app->db->beginTransaction();
try {
for($i=1;$i<=3;$i++){
$test = new Areas();
$test->name = 'name'.$i;
$test->sort=1;
if($test->save()){
echo "save $i | ";
}
}
$test = new Areas();
$test->name = 'ab'.$i;
$test->sorta=1; //寫入不存在的字段
if(!$test->save()){
"save fail"; //如果沒有寫入就輸出
}
//提交
$tr->commit();
} catch (Exception $e) {
//回滾
$tr->rollBack();
echo "rollback";
}
}
PHP實例運行結(jié)果
PHP實例
save 1 | save 2 | save 3 | rollback
PHP實例注意,因為最后的數(shù)據(jù)沒有插入成功,觸發(fā)了事務(wù)的回滾,所以數(shù)據(jù)表沒有新增數(shù)據(jù)產(chǎn)生.
PHP實例觸發(fā)事務(wù)回滾的原因是代碼出現(xiàn)了異常(Exception).
PHP實例處理數(shù)據(jù)失敗
PHP實例一般來講,我們的運行中的代碼是不會出現(xiàn)這種明顯的異常,這種異常會在開發(fā)測試過程中消滅掉.
PHP實例而真正造成數(shù)據(jù)需要回滾的是我們的某個業(yè)務(wù)出現(xiàn)問題,導致沒有寫入部分的數(shù)據(jù).
PHP實例
/**
* 測試事務(wù)
*/
public function actionTest(){
//創(chuàng)建事務(wù)
$tr = Yii::$app->db->beginTransaction();
try {
for($i=1;$i<=3;$i++){
$test = new Areas();
$test->name = 'name'.$i;
$test->sort=1;
if($test->save()){
echo "save $i | ";
}
}
$test = new Areas();
$test->name = null; //數(shù)據(jù)庫設(shè)計name不能為空,人為造成寫入失敗.
$test->sort=1; //寫入不存在的字段
if(!$test->save()){
echo "save fail"; //如果沒有寫入就輸出
}
//提交
$tr->commit();
} catch (Exception $e) {
//回滾
$tr->rollBack();
echo "rollback";
}
}
PHP實例運行結(jié)果如下,數(shù)據(jù)庫插入了三條數(shù)據(jù).
PHP實例
save 1 | save 2 | save 3 | save fail
PHP實例也就是說,如果因為業(yè)務(wù)邏輯導致某個數(shù)據(jù)表沒有寫入數(shù)據(jù),也沒有出現(xiàn)對應的回滾.
PHP實例改進方案如下
PHP實例
/**
* 測試事務(wù)
*/
public function actionTest(){
//創(chuàng)建事務(wù)
$tr = Yii::$app->db->beginTransaction();
try {
for($i=1;$i<=3;$i++){
$test = new Areas();
$test->name = 'name'.$i;
$test->sort=1;
if($test->save()){
echo "save $i | ";
}
}
$test = new Areas();
$test->name = null; //數(shù)據(jù)庫設(shè)計name不能為空,人為造成寫入失敗.
$test->sort=1; //寫入不存在的字段
if(!$test->save()){
throw new \yii\db\Exception(); //手動拋出異常,再由下面捕獲.
}
//提交
$tr->commit();
} catch (Exception $e) {
//回滾
$tr->rollBack();
echo "rollback";
}
}
PHP實例運行結(jié)果如下,數(shù)據(jù)庫沒有插入新數(shù)據(jù),事務(wù)被回滾.
PHP實例
save 1 | save 2 | save 3 | rollback
PHP實例分散的數(shù)據(jù)處理
PHP實例由于實際項目的復雜程度,導致我們的數(shù)據(jù)庫操作分散在不同的Model中.
PHP實例所以,實際項目的代碼不會是上面的樣子.
PHP實例模擬需求
PHP實例接收參數(shù):
PHP實例名字
PHP實例性別
PHP實例簽名
PHP實例業(yè)務(wù)處理流程:
PHP實例接收參數(shù)
PHP實例由發(fā)號器得到用戶的uid,發(fā)號器對應數(shù)據(jù)表增加一位數(shù)字
PHP實例把名字、性別、簽名和上一步的uid寫入用戶信息表
PHP實例初始化用戶余額表
PHP實例回滾觸發(fā)時機:
PHP實例初始化余額表沒有傳入uid導出沒有寫入數(shù)據(jù)
PHP實例實際代碼
PHP實例
//Controller
/**
* 測試事務(wù)-注冊用戶
*/
public function actionReg()
{
//獲取請求
$request = Yii::$app->request;
//設(shè)定返回格式
$response = Yii::$app->response;
$response->format = \yii\web\Response::FORMAT_JSON; //返回json
//測試代碼,去掉驗證身份步驟
$name = $request->get("name");
$gender = $request->get("gender");
$sign = $request->get("sign");
//測試代碼,省略參數(shù)校驗步驟
$tr = Yii::$app->db->beginTransaction();
try {
//得到uid
$uid = App::getSeNo();
UserProfile::add($uid, $name, $gender, 1, $sign);
$user_balance = UserBalance::initUserBalance($uid);
$tr->commit(); //提交數(shù)據(jù)
} catch (Exception $e) {
//回滾
$tr->rollBack();
return $e->getMessage(); //返回自定義異常信息
}
return $user_balance;
}
//UserProfile
/**
* 添加用戶信息
* @param $user_id
* @param $nikename
* @param $gender
* @param $user_type
* @param string $intro
* @return UserProfile
* @throws \Exception
*/
public static function add($user_id, $nikename, $gender,$user_type,$intro="") {
$model = new UserProfile();
$model->gender = $gender;
$model->nikename = $nikename;
$model->user_id = $user_id;
$model->user_type=$user_type;
$model->intro=$intro;
$model->update_time = time();
$insert =$model->insert();
if(!$insert){
throw new Exception("沒有寫入用戶資料");
}
return $model;
}
//UserBalance
/**
* 初始化用戶的可提現(xiàn)余額
* @param $user_id
*/
public static function initUserBalance($user_id){
$info=self::find()->where(['user_id'=>$user_id])->one();
if(!$info ){
$model=new UserBalance();
$model->user_id = $user_id;
$model->price= "0";
$model->update_time=time();
$insert = $model->insert();
if(!$insert){
throw new Exception("沒有初始化用戶余額");
}
$info=$model;
}
return $info->attributes;
}
PHP實例正常的結(jié)果如下
PHP實例
{"id":124,"user_id":1473179883,"price":"0","update_time":1473179883}
PHP實例如果把初始化用戶余額部分的user_id沒有傳遞成功,返回的結(jié)果如下
PHP實例
"沒有初始化用戶余額"
PHP實例我們可以針對具體情況定位到錯誤所在位置,及時修改.
PHP實例事務(wù)(Transaction)
PHP實例從上面的實際代碼可以看出,創(chuàng)建了事務(wù),只要在范圍內(nèi),就算是引入的別的Model也能把異常NG返回,完成回滾操作.
PHP實例一般情況下,整個Yii應用使用了同一個數(shù)據(jù)庫連接,或者說是使用了單例.
PHP實例而在yii\db\Connection中,又對事務(wù)對象進行了緩存:
PHP實例
class Connection extends Component
{
// 保存當前連接的有效Transaction對象
private $_transaction;
// 已經(jīng)緩存有事務(wù)對象,且事務(wù)對象有效,則返回該事務(wù)對象
// 否則返回null
public function getTransaction()
{
return $this->_transaction && $this->_transaction->getIsActive() ? $this->_transaction : null;
}
// 看看啟用事務(wù)時,是如何使用事務(wù)對象的
public function beginTransaction($isolationLevel = null)
{
$this->open();
// 緩存的事務(wù)對象有效,則使用緩存中的事務(wù)對象
// 否則創(chuàng)建一個新的事務(wù)對象
if (($transaction = $this->getTransaction()) === null) {
$transaction = $this->_transaction = new Transaction(['db' => $this]);
}
$transaction->begin($isolationLevel);
return $transaction;
}
}
PHP實例因此,可以認為整個Yii應用,使用了同一個 Transaction 對象,也就是說, Transaction::_level 在整個應用的生命周期中,是有延續(xù)性的. 這是實現(xiàn)事務(wù)嵌套的關(guān)鍵和前提.
PHP實例以上所述是小編給大家介紹的Yii2中事務(wù)的使用實例代碼詳解,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的.在此也非常感謝大家對維易PHP網(wǎng)站的支持!
轉(zhuǎn)載請注明本頁網(wǎng)址:
http://www.snjht.com/jiaocheng/3933.html