PHP的文件锁在单服务器的时候使用是什么任何问题的,当多服务时,PHP的文件锁就无法满足需求,一个服务器锁了另外一台服务器并且不知道有锁,从而导致锁失效, 而Redis共享锁可以满足。

redis-php-lock-1.png

1、实现PHP的Redis锁

1) 首先安装好Redis服务

2) 下载PHP连接Redis组件,下载地址https://github.com/sash/php-redis

3)实现php代码

<?php

require "Redis.php";

class Lock { 

     protected $db; 

     /** 

     * @var 锁时间 

     */ 

     protected $timeout = 10; 

      /** 

     * @var 最大锁时间 

     */ 

     protected $maxTimeout; 

     /** 

     * @var 过期时间 

     */ 

     protected $expireTime = 0; 

     /** 

     * @var 键 

     */

    protected $key;


    /** 

     * 读取超时时间 

     */

    public function getTimeOut() 

    { 

        return $this->timeout + time(); 

    }


    /** 

     * 设置超时时间 

     */

    public function setTimeout($second) 

     { 

         $this->timeout = $second > $this->maxTimeout ? $this->maxTimeout : $second; 

         return true; 

     }


      /** 

     * 存储当前锁的过期时间,用于解锁 

     */

    public function setExpireTime($time) 

     { 

         $this->expireTime = $time; 

         return true; 

     } 


      /** 

     * 获取当前锁的过期时间,用于解锁 

     */

     public function getExpireTime() 

     { 

         return $this->expireTime; 

     }


    public function __construct($maxTimeout = 120)

     { 

         $this->db = new Redis(); //这里可以做成单例 

         $this->maxTimeout = $maxTimeout; 

     }


      /** 

     * 锁

     * @param string $key 锁名

     * @param int $waitTimeOut 等待时间,默认是阻塞(一直等待)  

     */

     public function lock($key, $waitTimeOut = null) 

     { 

         $key = $this->getKey($key); 

         if (!$key || $this->key) return false; 

         $this->key = $key; //如果设置了超时时间 

         if (is_numeric($waitTimeOut)) $waitTimeOut = time() + $waitTimeOut; 

         do { 

             if ($lockStatus = $this->db->setnx($this->key, $this->getTimeOut())) { 

                 if ($this->db->expire($this->key, $this->maxTimeout)) { 

                     break; 

                 } 

             } 

             if ($lockStatus = $this->recover()) {//如果覆盖成功 

                 break;

             } 

             usleep(200); //睡眠处理 

         } while(!is_numeric($waitTimeOut) || $waitTimeOut >= time()); 

         if (!$lockStatus) return false; 

         $this->setExpireTime($this->db->get($key)); //设置当前的过期时间, 用于释放所 

         return true; 

     }


      /** 

     * 尝试覆盖已有的锁

     */

    protected function recover() 

     { 

         if (($expireTime = $this->db->get($this->key)) > time()) { //如果没有过期,直接返回 

             return false; 

         } 

         if ($currentTime = $this->db->getset($this->key, $this->getTimeOut())) {

             $this->db->expire($this->key, $this->getMaxTimeout()); 

         } 

         if ($currentTime != $expireTime) {//说明设置当前覆盖成功 

             return false; 

         } 

         return true; 

     }


      /** 

     * 解锁

     */

    public function unlock() 

     { 

         if ($this->getExpireTime() >= time() && !$this->db->del($this->key)) { 

             return false; 

         } 

         $this->key = null; 

         return true; 

     } 

      /** 

     * 获取锁名

     */

    protected function getKey($key) 

     { 

         if (empty($key) || !is_string($key)) { 

             return false; 

         } 

         return "Lock:{$key}"; 

     }

}

//测试代码,开多个页面进行测试

$timeOut = !empty($_GET['t']) ? (int)$_GET['t'] : null; //等待时间不传就是阻塞

$lock = new Lock(); 

if (!$lock->lock('test3', $timeOut)) { 

 echo 'Locking'; 

 exit(); 

 sleep(6); 

echo 'ok'; 

 $lock->unlock();

?> 

版权声明:未经博主允许不得转载。http://smister.com/post-48/redis-php-lock.html