tp3.2中悲觀鎖和樂觀鎖

悲觀鎖和樂觀鎖

業(yè)務(wù)邏輯的實(shí)現(xiàn)過程中,往往需要保證數(shù)據(jù)訪問的排他性。如在金融系統(tǒng)的日終結(jié)算處理中,我們希望針對(duì)某個(gè)時(shí)間點(diǎn)的數(shù)據(jù)進(jìn)行處理,而不希望在結(jié)算進(jìn)行過程中(可能是幾秒種,也可能是幾個(gè)小時(shí)),數(shù)據(jù)再發(fā)生變化。此時(shí),我們就需要通過一些機(jī)制來保證這些數(shù)據(jù)在某個(gè)操作過程中不會(huì)被外界修改,這樣的機(jī)制,在這里,也就是所謂的 “ 鎖 ” ,即給我們選定的目標(biāo)數(shù)據(jù)上鎖,使其無法被其他程序修改。 ThinkPHP支持兩種鎖機(jī)制:即通常所說的 “ 悲觀鎖( Pessimistic Locking ) ”和 “ 樂觀鎖( Optimistic Locking ) ” --摘自tp官網(wǎng)

悲觀鎖( Pessimistic Locking ) 適用于查詢和更新 配合回滾事務(wù)

悲觀鎖,正如其名,它指的是對(duì)數(shù)據(jù)被外界(包括本系統(tǒng)當(dāng)前的其他事務(wù),以及來自外部系統(tǒng)的事務(wù)處理)修改持保守態(tài)度,因此,在整個(gè)數(shù)據(jù)處理過程中,將數(shù)據(jù)處于鎖定狀態(tài)。悲觀鎖的實(shí)現(xiàn),往往依靠數(shù)據(jù)庫提供的鎖機(jī)制(也只有數(shù)據(jù)庫層提供的鎖機(jī)制才能真正保證數(shù)據(jù)訪問的排他性,否則,即使在本系統(tǒng)中實(shí)現(xiàn)了加鎖機(jī)制,也無法保證外部系統(tǒng)不會(huì)修改數(shù)據(jù))。
通常是使用for update子句來實(shí)現(xiàn)悲觀鎖機(jī)制。
例子:SELECT `id`,`wuser_id`,`out_trade_no`,`total`,`is_benefit` FROM `bj_injuryorder` WHERE `id` = 1 LIMIT 1 FOR UPDATE

ThinkPHP支持悲觀鎖機(jī)制,默認(rèn)情況下,是關(guān)閉悲觀鎖功能的,要在查詢和更新的時(shí)候啟用悲觀鎖功能,可以通過使用之前提到的查詢鎖定方法,例如:
$User->lock(true)->save($data);// 使用悲觀鎖功能

樂觀鎖( Optimistic Locking )

使用樂觀鎖呢有幾個(gè)條件:

1.繼承Think\Model\AdvModel類 高級(jí)模型

namespace Home\Model;
use Think\Model\AdvModel;
class UserModel extends AdvModel{
}

2.定義模型的optimLock屬性

默認(rèn)的optimLock屬性是 lock_version,也就是說如果要在User表里面啟用樂觀鎖機(jī)制,只需要在User表里面增加lock_version字段,如果有已經(jīng)存在的其它字段作為樂觀鎖用途,可以修改模型類的optimLock屬性即可。如果存在optimLock屬性對(duì)應(yīng)的字段,但是需要臨時(shí)關(guān)閉樂觀鎖機(jī)制,把optimLock屬性設(shè)置為false就可以了

3.數(shù)據(jù)表字段里面增加相應(yīng)的字段 只需要在User表里面增加lock_version字段

實(shí)例:

悲觀鎖:http://www.itdecent.cn/p/d200452b2877

樂觀鎖:

我自己總結(jié)的呢 就是加鎖執(zhí)行 必須先執(zhí)行完第一個(gè)操作才會(huì)執(zhí)行下一個(gè)操作 即測(cè)試時(shí)的sleep 或者 事務(wù)操作完成后或者其他的操作完成之后


mysql:
SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for bj_ceshi
-- ----------------------------
DROP TABLE IF EXISTS `bj_ceshi`;
CREATE TABLE `bj_ceshi` (
  `member_no` varchar(255) NOT NULL DEFAULT '',
  `money` decimal(10,0) DEFAULT NULL,
  `lock_version` int(255) DEFAULT NULL,
  `source` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`member_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

DemoController.class.php
/**
 * demo
 */
namespace WxShop\Controller;
use Think\Controller;
class DemoController extends Controller{
    public function demo()
    {
        
        $Test = D('Demo');  //測(cè)試樂觀鎖,已繼承AdvModel
        
        $data = $Test->find('hxl');
        $update = array(
                'member_no' => $data['member_no'],  //主鍵
                'money' => $data['money'] + 1,      //金額
                'source' => $data['source'] + 1 );                    //來源, 開兩個(gè)瀏覽器5秒內(nèi)分別點(diǎn)擊add鏈接方法,1為第一次,2為第二次
        
        sleep(30); //延時(shí)測(cè)試
        
        $flag = $Test->save($update);
        
        echo date('Y-m-d H:i:s');
        echo '<br/>';
        echo 'lock_version:' . $data['lock_version']; //輸出版本號(hào)
        echo '<br/>';
        echo 'result: '. $flag;                        //輸出結(jié)果標(biāo)記
        
        if($flag){
            
        }
        else{
            echo $Test->getError();
            echo $Test->getDbError();
        }
    }
}
DemoModel.class.php
<?php
namespace WxShop\Model;
use Think\Model\AdvModel;
class DemoModel extends AdvModel{
    protected $tableName = 'ceshi';//如果表名不是Model的名 可以在這里設(shè)置
    Protected $pk = 'member_no';//繼承的普通Model會(huì)自動(dòng)獲取主鍵  Adv的話如果主鍵不是id需要設(shè)置主鍵
    
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容