php結合redis實現秒殺功能


<?php
第一種,簡單實現
$conn =mysql_connect( "localhost" , "big" , "123456" );
if (! $conn ){
     echo "connect failed" ;
     exit ;
}
mysql_select_db( "big" , $conn );
mysql_query( "set names utf8" );
 
$price =10;
$user_id =1;
$goods_id =1;
$sku_id =11;
$number =1;
 
//生成唯一訂單
function build_order_no(){
   return date ( 'ymd' ). substr (implode(NULL, array_map ( 'ord' , str_split ( substr (uniqid(), 7, 13), 1))), 0, 8);
}
//記錄日志
function insertLog( $event , $type =0){
     global $conn ;
     $sql ="insert into ih_log(event,type)
     values( '$event' , '$type' )";
     mysql_query( $sql , $conn );
}
 
//模擬下單操作
//庫存是否大於0
$sql = "select number from ih_store where goods_id='$goods_id' and sku_id='$sku_id'" ; //解鎖 此時ih_store數據中goods_id='$goods_id' and sku_id='$sku_id' 的數據被鎖住(注3),其它事務必須等待此次事務 提交后才能執行
$rs =mysql_query( $sql , $conn );
$row =mysql_fetch_assoc( $rs );
if ( $row [ 'number' ]>0){ //高並發下會導致超賣
     $order_sn =build_order_no();
     //生成訂單
     $sql ="insert into ih_order(order_sn,user_id,goods_id,sku_id,price)
     values( '$order_sn' , '$user_id' , '$goods_id' , '$sku_id' , '$price' )";
     $order_rs =mysql_query( $sql , $conn );
     
     //庫存減少
     $sql = "update ih_store set number=number-{$number} where sku_id='$sku_id'" ;
     $store_rs =mysql_query( $sql , $conn );
     if (mysql_affected_rows()){
         insertLog( '庫存減少成功' );
     } else {
         insertLog( '庫存減少失敗' );
     }
} else {
     insertLog( '庫存不夠' );
}
?>.
第二種,使用mysql鎖行的方式
 
<?php
$conn =mysql_connect( "localhost" , "big" , "123456" );
if (! $conn ){
     echo "connect failed" ;
     exit ;
}
mysql_select_db( "big" , $conn );
mysql_query( "set names utf8" );
 
$price =10;
$user_id =1;
$goods_id =1;
$sku_id =11;
$number =1;
 
//生成唯一訂單號
function build_order_no(){
   return date ( 'ymd' ). substr (implode(NULL, array_map ( 'ord' , str_split ( substr (uniqid(), 7, 13), 1))), 0, 8);
}
//記錄日志
function insertLog( $event , $type =0){
     global $conn ;
     $sql ="insert into ih_log(event,type)
     values( '$event' , '$type' )";
     mysql_query( $sql , $conn );
}
 
//模擬下單操作
//庫存是否大於0
mysql_query( "BEGIN" );   //開始事務
$sql = "select number from ih_store where goods_id='$goods_id' and sku_id='$sku_id' FOR UPDATE" ; //此時這條記錄被鎖住,其它事務必須等待此次事務提交后才能執行
$rs =mysql_query( $sql , $conn );
$row =mysql_fetch_assoc( $rs );
if ( $row [ 'number' ]>0){
     //生成訂單
     $order_sn =build_order_no();
     $sql ="insert into ih_order(order_sn,user_id,goods_id,sku_id,price)
     values( '$order_sn' , '$user_id' , '$goods_id' , '$sku_id' , '$price' )";
     $order_rs =mysql_query( $sql , $conn );
     
     //庫存減少
     $sql = "update ih_store set number=number-{$number} where sku_id='$sku_id'" ;
     $store_rs =mysql_query( $sql , $conn );
     if (mysql_affected_rows()){
         insertLog( '庫存減少成功' );
         mysql_query( "COMMIT" ); //事務提交即解鎖
     } else {
         insertLog( '庫存減少失敗' );
     }
} else {
     insertLog( '庫存不夠' );
     mysql_query( "ROLLBACK" );
}
?>
 
第三種,使用非阻塞的文件排他鎖
 

<?php
$conn=mysql_connect("localhost","root","123456");
if(!$conn){
    echo "connect failed";
    exit;
}
mysql_select_db("big-bak",$conn);
mysql_query("set names utf8");
 
$price=10;
$user_id=1;
$goods_id=1;
$sku_id=11;
$number=1;
 
//生成唯一訂單號
function build_order_no(){
  return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
}
//記錄日志
function insertLog($event,$type=0){
    global $conn;
    $sql="insert into ih_log(event,type)
    values('$event','$type')";
    mysql_query($sql,$conn);
}
 
$fp = fopen("lock.txt", "w+");
if(!flock($fp,LOCK_EX | LOCK_NB)){
    echo "系統繁忙,請稍后再試";
    return;
}
//下單
$sql="select number from ih_store where goods_id='$goods_id' and sku_id='$sku_id'";
$rs=mysql_query($sql,$conn);
$row=mysql_fetch_assoc($rs);
if($row['number']>0){//庫存是否大於0
    //模擬下單操作
    $order_sn=build_order_no();
    $sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price)
    values('$order_sn','$user_id','$goods_id','$sku_id','$price')";
    $order_rs=mysql_query($sql,$conn);
     
    //庫存減少
    $sql="update ih_store set number=number-{$number} where sku_id='$sku_id'";
    $store_rs=mysql_query($sql,$conn);
    if(mysql_affected_rows()){
        insertLog('庫存減少成功');
        flock($fp,LOCK_UN);//釋放鎖
    }else{
        insertLog('庫存減少失敗');
    }
}else{
    insertLog('庫存不夠');
}
fclose($fp);

 

第四種,使用redis隊列

 

<?php
$store =1000;
$redis = new Redis();
$result = $redis ->connect( '127.0.0.1' ,6379);
$res = $redis ->llen( 'goods_store' );
echo $res ;
$count = $store - $res ;
for ( $i =0; $i < $count ; $i ++){
     $redis ->lpush( 'goods_store' ,1);
}
echo $redis ->llen( 'goods_store' );
?>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM