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

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

mysql lock table/unlock table 表鎖/解鎖

2019-11-11 01:43:43
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

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

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

 代碼如下復(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!';    }

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

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

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

說(shuō)到這里,請(qǐng)不要以為鎖表有多么高深,其實(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)前線程鎖定的所有表會(huì)自動(dòng)被解鎖。 

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

已經(jīng)是有種隊(duì)列的味道,對(duì)不,所以解決方案很簡(jiǎn)單嘛,在select前加鎖,執(zhí)行完后面邏輯代碼后解鎖。或許有沒(méi)有人會(huì)有一個(gè)疑問(wèn),就是如果萬(wàn)一鎖表后線程就斷掉了那么是不是就一直鎖表了,這個(gè)確實(shí)是可能存在但是既然你想到了那么數(shù)據(jù)庫(kù)的設(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();

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

 

 代碼如下復(fù)制代碼
   /**    * 鎖表    * @param string $table 表名    * @param int $type 讀鎖1還是寫(xiě)鎖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ā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 灌阳县| 商水县| 鸡东县| 平舆县| 临湘市| 顺平县| 定远县| 仲巴县| 嵊州市| 嵩明县| 德令哈市| 富顺县| 酒泉市| 紫云| 康保县| 新宾| 清涧县| 共和县| 汝城县| 临朐县| 平顶山市| 广宗县| 博客| 临朐县| 万州区| 嵩明县| 南宫市| 余干县| 大理市| 清徐县| 通城县| 民勤县| 尉氏县| 衡东县| 万载县| 牙克石市| 滨海县| 淮阳县| 冕宁县| 偏关县| 渑池县|