前段时间学习有了解到高并发的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