一、加排它锁
$pdo=new PDO("mysql:dbname=demo;host=localhost","root","root");
$pdo->query('SET NAMES utf8');
$redis=new Redis();
$redis->connect('127.0.0.1', 6379);
$num=$redis->get("num");
if($num<=12)//假定库存只有12个
{
sleep(2);
$sql = "select * from goods where id=1 for update";
$stmt = $pdo->query($sql);
$res=$stmt->fetch(2);
if($res['num'])
{ $redis->incr('num');
$stmt = $pdo->exec("update goods set num=num-1 where id=1");
//自行写各种业务处理。。。
}
}
else{
echo "抢购结束";
}
二、php+redis乐观锁
$pdo=new PDO("mysql:dbname=demo;host=localhost","root","root");
$pdo->query('SET NAMES utf8');
$redis=new Redis();
$redis->connect('127.0.0.1', 6379);
$uid=md5(mt_rand(1,1000000));//模拟生成用户id
var_dump($redis->lrange('user',0,-1));
$num=$redis->get("num");
// $redis->del("num");
// $redis->del("user");
//die;
if($num>=3) exit("抢购结束");//假设只有3个库存量
$redis->watch('num');//监听key的变化,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断
//开始事务
$redis->multi();
$redis->incr('num');
sleep(2);
$result=$redis->exec(); //返回true表示执行成功,nil表示事务被中断
if($result)
{
$stmt = $pdo->exec("update goods set num=num-1 where id=1");
if($stmt){
echo "抢购成功";
$redis->lpush("user",$uid);//记录抢购成功的用户id
//自行写各种业务处理。。。
}
}
经过ab压测后,就再也不会出现超卖的情况啦,哈哈
三、最后一个用文件锁,性能也是最低的,不推荐使用
$redis=new Redis();
$redis->connect('127.0.0.1',6379);
$num=$redis->get('num');//购买数量
$ku=1;//库存量
if($num
$file=fopen('1.lock',"a");
if(flock($file,LOCK_EX))
{
$store=$redis->incr('num');
fwrite($file,$store);
sleep(5);
//自行写各种业务处理。。。
flock($file,LOCK_UN);
}
fclose($file);
}