发现很多项目都有一个漏洞:比如账户A有100元,账户B有0元,然后从账户A转100元给账户B,正常的代码流程是,先检测账户A余额是否足够,然后从账户A中扣除100元,再给账户B增加100元,结果变成账户A剩下0元,账户B剩下100元,转账操作成功,逻辑上并没有问题,但是,如果该转账请求瞬间执行30次,结果发现其中大约有4、5次都是成功的,其余的请求则会报余额不足,原因是那4、5次成功的请求中余额不足的判断是同一时间执行的,所以都可以通过,假如有5次都通过了,结果很有可能就变成,账户A扣除5×100元(余额-400元),账户B增加了5×100元(余额500元),这样问题就大了,我们期望的结果是,无论瞬间请求多少次都要保证只有一次可以通过余额不足的检测,那么解决的办法就是让这段代码队列执行。
在PHP中让代码队列执行最常用的方法就是非阻塞的文件排他锁,示例如下:
//非阻塞的文件排他锁 $fp = fopen("/lock.txt", "w+"); if(!flock($fp, LOCK_EX | LOCK_NB)){ echo '系统繁忙'; exit(); } //读取用户余额,判断是否足够 //...... if(){ //余额足够 //执行转账逻辑 //...... flock($fp, LOCK_UN); //释放锁 echo '转账成功'; }else{ echo '余额不足'; } fclose($fp);