php实现redis分布式锁

前段时间学习有了解到高并发的redis分布式锁,刚好有看到博客上看到,认为还不错,所以在这里分享一下,不多说,直接上代码
第一种:

<?php
namespace app\index\controller;
use think\Db;
use think\Controller;
class Index extends Controller
{
    private $redis;//redis实例对象
    private $key;
    private $lock_key;//锁的名称

    //默认锁的有效时长
    private $lockExpires = 60;//有效时间
    private $locked; //锁的状态

    function __construct()
    {
        // parent::__construct($request);
        $this->redis = new \Redis();
        $this->redis->connect('127.0.0.1',6379,120);
        $this->redis->auth('liuduoduo');
    }


    public function index()
    {
        $key="liuduoduo";
        $this->key = $result = $this->redis->get($key);
        $this->lock_key = "lock:".$key;

        if (empty($result)) {
            //设置锁值为当前时间戳he有效期
            $lockValue = time() + $this->lockExpires;
            // halt(222);
            /**
             * 创建锁
             * 试图以lockkey为key创建一个缓存,value值为当前时间戳
             * 由于setnx()函数只有在不存在当前key的缓存时才会创建成果
             * 所以,用此函数就可以判断当前执行的操作是否已经有其他进程在执行了
             */
            $lock =  $this->redis->setnx($this->lock_key,$lockValue);
            /**
             * 满足两个条件中的一个即可进行操作
             * 1.上一步创建锁成果
             * 2.1  判断锁的值(时间戳)是否小于当前时间戳 $this->redis->get()
             * 2.2  同时给锁设置新值
             */
            // halt($lock);
            if (!empty($lock) || ($this->redis->get($key)) < time() && $this->redis->getSet($this->lock_key,$lockValue) < time() ) {
                //给锁设置生存时间
                halt($this->redis->expire($this->lock_key,$this->lockExpires));
                // halt(111);
                //******************************
                //此处执行插入、更新缓存操作...
                //******************************

                //以上程序走完删除锁
                //检测锁是否过期,过期锁要删除
                if ($this->redis->ttl($lockValue)) {
                    $this->redis->del($lockValue);
                    $this->$locked = false;
                }
            }
        }

    }

}

第二种

<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2020-08-03
 * Time: 15:27
 */

include_once('./predis-1.1/autoload.php');

class RedisMutexLock
{

    //存储对象
    protected static  $connect;

    /**
     * 缓存 Redis 连接。
     *
     * @return void
     */
    public static function getRedis()
    {
        if (empty($connect)){
            $cluster_arr = [
                '127.0.0.1:6380',
                '127.0.0.1:6381',
                '127.0.0.1:6382'
            ];
            self::$connect  = new Predis\Client($cluster_arr, array('cluster'=>'redis'));
        }

        // 这行代码请根据自己项目替换为自己的获取 Redis 连接。
        return self::$connect;
    }

    /**
     * 获得锁,如果锁被占用,阻塞,直到获得锁或者超时。
     * -- 1、如果 $timeout 参数为 0,则立即返回锁。
     * -- 2、建议 timeout 设置为 0,避免 redis 因为阻塞导致性能下降。请根据实际需求进行设置。
     *
     * @param  string  $key         缓存KEY。
     * @param  int     $timeout     取锁超时时间。单位(秒)。等于0,如果当前锁被占用,则立即返回失败。如果大于0,则反复尝试获取锁直到达到该超时时间。
     * @param  int     $lockSecond  锁定时间。单位(秒)。
     * @param  int     $sleep       取锁间隔时间。单位(微秒)。当锁为占用状态时。每隔多久尝试去取锁。默认 0.1 秒一次取锁。
     * @return bool 成功:true、失败:false
     */
    public static function lock($key, $timeout = 0, $lockSecond = 20, $sleep = 100000)
    {
        if (strlen($key) === 0) {
            // 项目抛异常方法
            throw  new Exception('缓存KEY没有设置');
        }
        $start = self::getMicroTime();
        $redis = self::getRedis();
        do {
            // [1] 锁的 KEY 不存在时设置其值并把过期时间设置为指定的时间。锁的值并不重要。重要的是利用 Redis 的特性。
            $acquired = $redis->setex("Lock:{$key}", $lockSecond, 1);
            if ($acquired) {
                break;
            }
            if ($timeout === 0) {
                break;
            }
            usleep($sleep);
        } while (!is_numeric($timeout) || (self::getMicroTime()) < ($start + ($timeout * 1000000)));
        return $acquired ? true : false;
    }

    /**
     * 释放锁
     *
     * @param  mixed  $key  被加锁的KEY。
     * @return void
     */
    public static function release($key)
    {
        if (strlen($key) === 0) {
            // 项目抛异常方法
            throw  new Exception('缓存KEY没有设置');
        }
        $redis = self::getRedis();
        $redis->del("Lock:{$key}");
    }

    /**
     * 获取当前微秒。
     *
     * @return bigint
     */
    protected static function getMicroTime()
    {
        return bcmul(microtime(true), 1000000);
    }
}

RedisMutexLock::lock('duoduo1');
RedisMutexLock::lock('duoduo2');
RedisMutexLock::lock('duoduo3');
RedisMutexLock::release('duoduo3');

如果需要深入学习的,可以看这篇文章 https://blog.csdn.net/zeicool/article/details/79613352
转之
https://blog.csdn.net/panjiapengfly/article/details/84758971
https://www.cnblogs.com/starluke/p/11733220.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值