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

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

mysql lock table/unlock table 表鎖/解鎖

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

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

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

 代碼如下復(fù)制代碼

    $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!';    }

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

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

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

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

    LOCK TABLE `table` [READ|WRITE]

解鎖

    UNLOCK TABLES;

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

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

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

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

好,看下改進(jìn)后的代碼。

   

 代碼如下復(fù)制代碼
$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();

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

 

 代碼如下復(fù)制代碼
   /**    * 鎖表    * @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ā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 宜宾县| 新津县| 黔东| 筠连县| 陕西省| 高邑县| 深水埗区| 淮安市| 禄丰县| 灵台县| 民丰县| 南部县| 沂南县| 河东区| 寿阳县| 凤山县| 苍南县| 龙口市| 莎车县| 扶沟县| 河南省| 隆林| 太康县| 曲松县| 金平| 西乌珠穆沁旗| 柘城县| 饶平县| 娄底市| 大方县| 山阴县| 邯郸县| 大姚县| 谷城县| 晋城| 宁阳县| 商水县| 保德县| 溧阳市| 巴彦淖尔市| 长治县|