| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- <?php
- namespace common\libs\lock;
- use Yii;
- use yii\base\BaseObject;
- use yii\base\StaticInstanceTrait;
- /**
- * Redis分布锁
- * 使用锁:
- * $key = 'lock';
- * if (!$lock->lock($key)) {
- * throw new Exception('error');
- * }
- */
- class RedisLock extends BaseObject {
- use StaticInstanceTrait;
- /**
- * 前缀
- */
- const KEY_PREFIX = 'BonusRedisLock:';
- /**
- * 重试次数,0:无限重试
- * @var int
- */
- public $retryCount = 0;
- /**
- * 获取锁失败重试等待的时间,微妙 ,1ms=1000us
- * @var int
- */
- public $retryInterval = 100000;
- /**
- * 获取锁失败,是否重试
- * @var bool
- */
- public $retry = true;
- /**
- * 锁的超时时间,防止死锁发生,应该是业务的最大处理时间
- * @var int
- */
- public $expire = 5;
- /**
- * Redis 对象
- * @var null
- */
- public $redis = null;
- /**
- * @inheritdoc
- */
- public function init() {
- parent::init();
- }
- /**
- * 获取redis对象
- * @return mixed|null
- */
- public function getRedis(){
- if(!is_null($this->redis)){
- return $this->redis;
- }
- $this->redis = Yii::$app->redis;
- return $this->redis;
- }
- /**
- * @return float
- */
- public static function microTime() {
- // 获取当前毫秒时间戳
- list ($s1, $s2) = explode(' ', microtime());
- $currentTime = (float) sprintf('%.0f', (floatval($s1) + floatval($s2)) * 1000);
- return $currentTime;
- }
- /**
- * @param $key
- * @return string
- */
- public static function getKey($key){
- return self::KEY_PREFIX . $key;
- }
- /**
- * 加锁
- * @param $key
- * @return bool
- */
- public function lock($key) {
- $count = 0;
- $key = self::getKey($key);
- while (true) {
- $nowTime = self::microtime();
- $lockValue = self::microtime() + $this->expire;
- $lock = $this->getRedis()->setnx($key, $lockValue);
- if (!empty($lock) || ($this->getRedis()->get($key) < $nowTime && $this->getRedis()->getset($key, $lockValue) < $nowTime )) {
- $this->getRedis()->expire($key, $this->expire);
- return true;
- } elseif ($this->retry && (($this->retryCount > 0 && ++$count < $this->retryCount) || ($this->retryCount == 0))) {
- usleep($this->retryInterval);
- } else {
- break;
- }
- }
- return false;
- }
- /**
- * 解锁
- * @param $key
- * @return bool
- */
- public function unlock($key) {
- $key = self::getKey($key);
- if ($this->getRedis()->ttl($key)) {
- return $this->getRedis()->del($key);
- }
- return true;
- }
- }
|