联系邮箱:254200493@qq.com 登录 注册

乐观锁实现抢购

2018-10-29 14:50:07

电影抢票、商品抢购是我们开发中经常会遇到的问题。实现的方法有很多,最直接的方法就是加锁(for update),当然这样的效率是比较低的,也是比较笨拙的办法。那有什么方法可以解决这个问题,同时在效率上又比较理想呢?

假设:电影表(film数据结构如下:

1、一般的逻辑下的写法ThinkPhp5的实现方法,以下内容均为tp5):

$id = input(“param.id”);

$film = Db::table(“film”)->where(‘id’,$id)->find();

if($film[‘tickets’]>0){

$film[‘tickets’] = $film[‘tickets’]-1;

$r = Db::table(“film”)->where(‘id’,$id)->update([‘tickets’=>$film[‘tickets’]+1]);

if($r){

return $this->success(“恭喜你,抢购成功!”);

}

}

return $this->error(“抢购失败!”);


这种方法貌似可行,但数据量一大就会发现出问题了?票数全都乱了......

2、直接加锁,即悲观锁

$id = input(“param.id”);

$film = Db::table(“film”)->where(‘id’,$id)->lock(true)->find();

if($film[‘tickets’]>0){

$film[‘tickets’] = $film[‘tickets’]-1;

$r = Db::table(“film”)->where(‘id’,$id)->update([‘tickets’=>$film[‘tickets’]+1]);

if($r){

return $this->success(“恭喜你,抢购成功!”);

}

}

return $this->error(“抢购失败!”);


这样可以解决问题,也就是所谓的悲观锁,但效率是比较低的。

3、乐观锁  

film表加一个字段version(int 10 unsigned),每次更新时version都要加1,具体的方法如下:

$id = input(“param.id”);

$film = Db::table(“film”)->where(‘id’,$id)->find();

if($film[‘tickets’]>0){

$film[‘tickets’] = $film[‘tickets’]-1;

$r = Db::table(“film”)->where(‘id’,$id)->where(‘version’,$film[‘version’])->update([‘tickets’=>$film[‘tickets’]+1,’version’=>$film[‘version’]+1]);

if($r){

return $this->success(“恭喜你,抢购成功!”);

}else{

//抢票失败,可重试。

}

}

return $this->error(“抢购失败!”);





相关文章