国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發(fā)設計 > 正文

mysql lock table/unlock table 表鎖/解鎖

2019-11-11 02:23:16
字體:
供稿:網(wǎng)友

在某個地方看到有個例子,具體描述類似如下:商店現(xiàn)在某商品只有1件庫存,然后A與B在網(wǎng)上進行下訂,A與B幾乎同時(或許也就差幾毫秒,A比B快那么一點點)進行。

很明顯是只有A才能成功下單的,B則會收到庫存不足的提示,但是作為放置在服務端的那個頁面(或者稱為腳本程序)我們得怎樣去處理這個問題呢?或者我先放出一段代碼吧。

 代碼如下復制代碼

    $sql = "select number from goods where id=1";    $number = intval( $db->result( $db->query( $sql ), 0 ) );    if ( $number > 0 ) {    sleep( 2 );    $sql = "update goods set number=number-1 where id = 1";    if ( $db->query( $sql ) ) {    echo 'Ok!Here you are!';    } else {    echo 'Sorry!Something go wrong!Try it again.';    }    } else {    echo 'No more!you are so late!';    }

這部分代碼除了缺少一定注釋外都寫得沒錯,當然$db是一個操作數(shù)據(jù)庫的類,我只是將大部分方法封裝了,這里的邏輯也是很明顯了。

先獲取id為1這個東東的庫存數(shù),看看是否為0,如果為0就訂購不成功了,如果大于0則將庫存減1然后提示ok。這確實沒有任何錯誤,邏輯也對。如果請求是一個接一個地產(chǎn)生的,那么什么問題都沒有,但當一些并發(fā)情況出現(xiàn)時就可能出現(xiàn)一些無厘頭的問題了。你想啊,是不是可能存在一種情況,A剛發(fā)出請求,腳本處理到update之前B又發(fā)出請求,那么現(xiàn)在庫存依然還有1,因為A的update還沒有執(zhí)行呢,所以$number不少于0,這次完了,B也下單了,于是庫存變成-1了(假設原來只有1件),確實是一個荒謬而且比較搞笑的結(jié)果。

出現(xiàn)問題的原因很明顯,就是忽略了這種并發(fā)情況的考慮,處理下訂應該是種隊列方式,也就是先來先得,就是說在執(zhí)行這個下訂動作是要排隊的,前面的那個先下訂然后后者才能下訂,當然當后者下訂前才再判斷庫存的數(shù)量。那么怎樣解決這個問題呢,在程序?qū)用嫔厦?#20284;真的沒有方法去解決這個問題,所以在此才提到鎖表的概念,上面出現(xiàn)這個問題的歸根于沒有控制一個select number的先后順序(或者可以這么說吧),因為在A執(zhí)行update之前你又允許B去查詢庫存,當然結(jié)果還是1,至少要等待A更新庫存后才允許其他人的任何操作,也就是對goods表進行一個排隊操作,對goods表進行鎖定。

說到這里,請不要以為鎖表有多么高深,其實它就是一條sql

    LOCK TABLE `table` [READ|WRITE]

解鎖

    UNLOCK TABLES;

引用專業(yè)的描述是

LOCK TABLES為當前線程鎖定表。 UNLOCK TABLES釋放被當前線程持有的任何鎖。當線程發(fā)出另外一個LOCK TABLES時,或當服務器的連接被關(guān)閉時,當前線程鎖定的所有表會自動被解鎖。 

如果一個線程獲得在一個表上的一個READ鎖,該線程和所有其他線程只能從表中讀。 如果一個線程獲得一個表上的一個WRITE鎖,那么只有持鎖的線程READ或WRITE表,其他線程被阻止。

已經(jīng)是有種隊列的味道,對不,所以解決方案很簡單嘛,在select前加鎖,執(zhí)行完后面邏輯代碼后解鎖。或許有沒有人會有一個疑問,就是如果萬一鎖表后線程就斷掉了那么是不是就一直鎖表了,這個確實是可能存在但是既然你想到了那么數(shù)據(jù)庫的設計人員也一定考慮到了,可以告訴你關(guān)于unlock的一些資料:當線程發(fā)出另一個 LOCK TABLES,或當與服務器的連接被關(guān)閉時,被當前線程鎖定的所有表將被自動地解鎖。這下放心了吧。

好,看下改進后的代碼。

   

 代碼如下復制代碼
$db->lock( 'goods', 2 );    $sql = "select number from goods where id=1";    $number = intval( $db->result( $db->query( $sql ), 0 ) );    if ( $number > 0 ) {    sleep( 2 );    $sql = "update goods set number=number-1 where id = 1";    if ( $db->query( $sql ) ) {    echo 'Ok!Here you are!';    } else {    echo 'Sorry!Something go wrong!Try it again.';    }    } else {    echo 'No more!you are so late!';    }    $db->unlock();

只加了兩行代碼,不過也不能這么說,因為paperen我修改了自己那個操作數(shù)據(jù)庫的類,加了兩個方法lock與unlock,其實這兩個方法也很簡單。

 

 代碼如下復制代碼
   /**    * 鎖表    * @param string $table 表名    * @param int $type 讀鎖1還是寫鎖2    */    public function lock( $table, $type = 1 ) {    $type = ( $type == 1 ) ? 'READ' : 'WRITE';    $this->query( "LOCK TABLE `$table` $type" );    }         /**    * 解鎖    */    public function unlock() {    $this->query( "UNLOCK TABLES" );    }

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 晋城| 遵义县| 通山县| 万宁市| 中卫市| 都匀市| 靖州| 通河县| 皋兰县| 秦皇岛市| 卫辉市| 钟祥市| 天气| 通辽市| 康平县| 长顺县| 古交市| 宁远县| 松江区| 刚察县| 鸡西市| 马鞍山市| 连江县| 玉林市| 新宾| 扎兰屯市| 博罗县| 云和县| 璧山县| 昆明市| 江津市| 梁平县| 济阳县| 岳普湖县| 宁远县| 宝兴县| 盐池县| 科技| 浙江省| 天水市| 桐柏县|