美文网首页
PHP文件锁

PHP文件锁

作者: 江河湖海琴瑟琵琶 | 来源:发表于2020-11-24 11:53 被阅读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

    相关文章

      网友评论

          本文标题:PHP文件锁

          本文链接:https://www.haomeiwen.com/subject/lqrrrktx.html