PHP文件锁

2020-11-24  本文已影响0人  江河湖海琴瑟琵琶

有时候需要避免代码并发执行.

缓存击穿问题.

比如一件商品编号1001.在缓存中它的key为goods:1001,请求时,如果缓存中不存在,就读数据库,并设置缓存

if (读缓存 == null){
    //读数据库
    //设置缓存
}

此时一万个用户并发访问,读缓存为空,那么一万个请求会同时到达数据库.
期望的是:缓存为空时,只有一个线程进入if判断,进行读库操作
java中有同步锁synchronized很容易就能实现.

php中可以用文件锁来达到同样的效果.

  1. 以缓存中的key作为文件名,生成一个文件.
  2. 给这个文件上锁.
  3. 判断上锁是否成功,成功则进行读库操作.
    代码如下
# FileLock.php
<?php
namespace lock;

class FileLock
{
    private $fp;//文件描述符
    /**
     * FileLock constructor.
     * @param string $key 缓存中的key,用来作为文件名
     */
    public function __construct ($key) {
        $this->makeFile($key);
    }

    /**
     * 生成一个文件
     * @param string $key 文件名
     */
    private function makeFile($key){
        $fp = fopen($key,'a');//生成文件,不存在就创建
        $this->fp = $fp;//记录描述符
    }

    /**
     * 获取锁
     * @ LOCK_EX 独占锁
     * @ LOCK_NB 获取锁失败时,不阻塞线程,直接返回
     * @return bool
     */
    public function getLock(){
        return flock($this->fp,LOCK_EX|LOCK_NB);
    }

    /**
     * 释放锁
     * @return bool
     */
    public function clearLock(){
        return flock($this->fp,LOCK_UN);
    }
}

测试效果

<?php
use lock\FileLock;
require_once 'FileLock.php';

if (!isset($argv[1])){
    echo '输入cacheKey';
    return;
}
//获取输入的cacheKey
$cacheKey = $argv[1];
$fileLock = new FileLock($cacheKey);

if ($fileLock->getLock())
{
    echo "读库-$cacheKey".PHP_EOL;
    sleep(60);
    //TODO 设置缓存
    $fileLock->clearLock();

}else{
    echo "获取锁失败$cacheKey";
}

执行结果

第一个终端 image.png 第二个 image.png 第三个 image.png
上一篇下一篇

猜你喜欢

热点阅读