zoukankan      html  css  js  c++  java
  • Redis锁功能代码

    <?php
    
    class Rediss {
    	private static  $_instance = null;
    	private function __construct(){
    		self::$_instance = new Redis();
    		$config = [
    			'host' => '127.0.0.1',
    			'port' => 6379
    		];
    		self::$_instance->connect($config['host'],$config['port']);
    		if(isset($config['password'])){
    			self::$_instance->auth($config['password']);
    		}
    	}
    
    	public static function instance(){
    		if(!self::$_instance){
    			 new self;
    		}
    
    		return self::$_instance;
    	}
    
    	private function __clone(){}
    }
    
    
    
    
    
    class ProcessRedisLock{
    /**
         * redis key 前缀
         */
        const KEY_PREFIX = 'PROCESS_REDIS_LOCK:';
    
        /**
         * 默认超时时间(秒)
         */
        const DEFAULT_TIMEOUT = 5;
    
        /**
         * 最大超时时间(秒)
         */
        const MAX_TIMEOUT_SETTING = 60;
    
        /**
         * 随机数的最小值
         */
        const MIN_RAND_NUM = 0;
    
        /**
         * 随机数的最大值
         */
        const RAND_MAX_NUM = 100000;
    
        /**
         * 每次取锁间隔毫秒数1-1000000
         */
        const GET_LOCK_SLEEP_MICRO_SECONDS = 10;
    
        /**
         * @var mixed redis 实例
         */
        private $redisIns;
    
        /**
         * @var string 锁名
         */
        private $lockName;
    
        /**
         * @var int 超时时间,不可超过 self::MAX_TIMEOUT_SETTING
         */
        private $timeout;
    
    
    
    	public function __construct($redisIns,$lockName,$timeout = self::DEFAULT_TIMEOUT){
            if (!$redisIns) {
                new Exception('The redis instance is empty');
            }
    
            if(!$lockName){
                throw new Exception('Lock name invalid');
            }
    
            // 校验超时时间
            $timeout = intval($timeout);
            if (!($timeout > 0 && $timeout <= self::MAX_TIMEOUT_SETTING)) {
                throw new Exception('The timeout interval is (0,' . self::MAX_TIMEOUT_SETTING . ']');
            }
    
            $this->redisIns = $redisIns;
            $this->lockName = $lockName;
            $this->timeout = $timeout;
    	}
    
    
    	   /**
         * 加锁
         * @return bool
         * @Date 2019/11/22
         */
        public function lock()
        {
            // redis key
            $key = $this->getRedisKey();
    
    
            // 唯一标志
            $id = $this->getId();
    
            // 超时时间
            $endTime = time() + $this->timeout;
    
            // 循环取锁
            while (time() < $endTime) {
                // 尝试加锁,若给定的 key 已经存在,则 SETNX 不做任何动作。
                if ($this->redisIns->setnx($key, $id)) {
                    // 设置过期时间,防止程序异常退出没有解锁导致死锁
                    $this->redisIns->expire($key, $this->timeout);
                    // 返回唯一标志,用于解锁
                    return $id;
                }
                usleep(self::GET_LOCK_SLEEP_MICRO_SECONDS);
            }
    
            return false;
        }
    
    
            /**
         * 解锁
         * @param string $id 唯一标志,加锁成功时返回
         * @return bool
         * @Date 2019/11/22
         */
        public function unlock($id)
        {
            $key = self::getRedisKey();
    
            // 如果锁的值与没有被修改
            if ($this->redisIns->get($key) == $id) {
                // 开始事务
                $this->redisIns->multi();
                // 释放该锁
                $this->redisIns->del($key);
                // 执行
                $this->redisIns->exec();
                return true;
            } else {
                return false;
            }
        }
    
    
          /**
         * 获取redis key
         * @return string
         * @Date 2019/11/22
         */
        public function getRedisKey()
        {
            return self::KEY_PREFIX . $this->lockName;
        }
    
        /**
         * 获取唯一标志位
         * @Date 2019/11/22
         */
        public function getId()
        {
            return uniqid(self::KEY_PREFIX) . mt_rand(self::MIN_RAND_NUM, self::RAND_MAX_NUM);
        }
    }
    
    
    class test {
    
    	public function testAction()
        {
            $params = $this->getRequest()->getParams();
            $this->requestTask($params['queryName'], $params['handlerTime'], $params['lockName'], $params['timeout']);
        }
    
        // 模拟取锁、耗时操作、释放锁
        public function requestTask($queryName, $handlerTime, $lockName, $timeout)
        {
            try {
                // 获取redis实例
            	//$aa = Rediss::instance();
                $processRedisLock = new ProcessRedisLock(Rediss::instance(), $lockName, $timeout);
    
                $this->echoAndSaveInfo($queryName, "try to get lock,timeover is {$timeout} seconds");
    
                // 取锁
                $id = $processRedisLock->lock();
                // 如果到了超时时间还未取到会返回false,则直接抛异常
                if($id === false){
                    throw new Exception('get Lock err');
                }
                
    
               // $this->echoAndSaveInfo($queryName, "get Lock success Id is:".$id);
    
                // 模拟耗时操作
                sleep($handlerTime);
    
                // 释放锁
                $processRedisLock->unlock($id);
               // $this->echoAndSaveInfo($queryName, "lockOut lock");
            } catch (Exception $e) {
                //$this->echoAndSaveInfo($queryName, $e->getMessage());
                // do something
            }
        }
    
        // 输出并且记录日志
        public function echoAndSaveInfo($queryName, $content)
        {
            $info = date('Y-m-d H:i:s') . " [{$queryName}]: {$content}" . PHP_EOL;
            echo $info;
            file_put_contents('test.txt', $info . PHP_EOL, FILE_APPEND);
        }
    }
    
        //1.分别用一个chrome和一个ie,模拟并发请求:
            //1)http://xxx/test?queryName=task1&handlerTime=10&lockName=myLocktest&timeout=10
           // 2)http://xxx/test?queryName=task2&handlerTime=10&lockName=myLocktest&timeout=5
    
    
    $a = new test();
    
    $a->requestTask('mytest',0.1,'locks',5);//锁名,模拟中间业务时间,
    

      

  • 相关阅读:
    SQLAlchemy Table(表)类方式
    MySQL简单入门
    第四次作业
    第三次随笔
    第二次随笔
    第一次随笔
    第四次随笔
    第三次作业
    第二次随笔
    第一次随笔
  • 原文地址:https://www.cnblogs.com/bing2017/p/13560133.html
Copyright © 2011-2022 走看看