Mysql的鎖機制與PHP文件鎖處理高併發簡單思路

以購買商品舉例:mysql

① 從數據庫獲取庫存的數量。
② 檢查一下庫存的數量是否充足。
③ 庫存的數量減去買家購買的數量(以每一個用戶購買一個爲例)。
④ 最後完成購買。sql

僅僅這幾行邏輯代碼在併發的狀況下會出現問題,本身能夠想象一下。
這裏暫時就不測試了,下面會針對併發的處理給出測試結果。
建立表:數據庫

CREATE TABLE `warehouse` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `stock` int(11) NOT NULL DEFAULT '0' COMMENT '庫存',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=utf8

第一種方案,使用Mysql的鎖(跟表引擎沒有關係)。
共享鎖:全部人能夠讀一個資源,但只有獲取鎖的人能夠操做;
排它鎖:只有得到所的對象能夠操做資源,其餘的不能操做,讀都不能夠。
語法:併發

LOCK TABLE a READ,b WRITE,c READ,d WRITE;(能夠鎖多張表,在鎖表的過程當中只能操做被鎖的表,不能操做其餘表)。
UNLOCK TABLES;(釋放表)。
@$mysql = mysql_connect('localhost','root','');
mysql_query('set names utf8');
mysql_select_db('test');
mysql_query('LOCK TABLE `warehouse` WRITE');  //鎖表以後同一時間只有一我的能操做,也就是隻有一我的能獲取到鎖
$sql = 'SELECT `stock` FROM warehouse';
$res = mysql_query($sql);
$row= mysql_fetch_array($res);
$stock = $row[0];
if( $stock < 1) {
    die('庫存不足');
}else{
    $new_stock = intval($stock - 1);
    mysql_query('UPDATE warehouse SET `stock` = '.$new_stock);
    mysql_query('UPDATE TABLES');
}

鎖表的缺點是:會出現阻塞,若是同時鎖多張表的話,還會影響整個網站相關表的加載。
第二種方案,使用PHP的文件鎖。
特色:當調用flock鎖一個文件時,若是沒有獲取鎖,直接返回FALSE,不會出現阻塞。
排它鎖:flock($fp,LOCK_EX);
共享鎖:flock($fp,LOCK_SH);
釋放鎖:flock($fp,LOCK_UN);測試

@$mysql = mysql_connect('localhost','root','');
mysql_query('set names utf8');
mysql_select_db('test');
$fp = fopen('./lock.txt','r');
$try = 10;  //聲明一個變量表示要獲取的次數,防止死循環
do{
    $lock = flock($fp, LOCK_EX);
    if(!$lock)
        usleep(5000); //若是沒有獲取到鎖,釋放CPU,休息5000毫秒
}while(!$lock && --$try >=0 );
    if($lock) {
    $sql = 'SELECT `stock` FROM warehouse';
    $res = mysql_query($sql);
    $row = mysql_fetch_array($res);
    $stock = $row[0];
    if( $stock < 1) {
        die('庫存不足');
    }else{
        $new_stock = intval($stock - 1);
        mysql_query('UPDATE warehouse SET `stock` = '.$new_stock);
    }
    flock($fp, LOCK_UN);
    fclose($fp);

}else{ die('系統繁忙!'); }

第三種方案,簡單的SQL語句就能夠避免倉庫爲負數。fetch

@$mysql = mysql_connect('localhost','root','');
mysql_query('set names utf8');
mysql_select_db('test');
mysql_query('UPDATE warehouse SET `stock` = `stock` -1 WHERE `stock` > 0');  //能夠避免庫存爲負數

測試的方法是,找到Apache下的ab.exe,拖入CMD終端,而後輸入指定參數測試。
具體參數說明Google一下你就知道,好比耗時之類的...這裏不作詳細說明。網站

clipboard.png
PS:Mysql的表鎖和PHP的文件鎖在應對併發數量上也有差異,本身能夠多測試。總之方案還有不少spa

相關文章
相關標籤/搜索