PHP 实现一个可用的redis 事务锁, 解决并发问题
程序员文章站
2024-01-05 11:15:52
...
调用代码
require("./redis_lock/RedisLock.php");
$redis_lock = new RedisLock("127.0.0.1", 6379);
$name = "goods";
$id = 100002;
$lock_name = $name.$id;
$redis_lock -> setLockName($lock_name,$id);
$redis_lock -> exe(function (){
echo "我抢到了\n";
},function (){
echo "我没有抢到\n";
});
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2019/9/17
* Time: 14:04
* Desc: redis 分布式事务锁, 非原子性操作
*/
class RedisLock
{
private $redis = null;
private $lock_name = "";
private $check_flag = "";
/**
* RedisLock constructor.
* @param $host string
* @param $port string|int
* @param string $pass
*/
public function __construct($host,$port,$pass = "")
{
$redis = new Redis();
$redis->connect($host, $port);
if (!empty($pass)){
$redis->auth($pass);
}
if (!$redis){
echo "redis create error!";
exit(1);
}
$this -> redis = $redis;
}
/**
* @param $name string 锁名称
* @param string $check_flag 校验参数
*/
public function setLockName($name, $check_flag = "1"){
$this -> lock_name = $name;
$this -> check_flag = $check_flag;
}
/**
* @param $callback
* @param $errCallback
* @param int $timeout 超时时间
* @param int $overCount 尝试次数
*/
public function exe($callback, $errCallback, $timeout = 10, $overCount = 3){
$count = 0;
do {
$key = $this -> lock_name;
$value = $this -> check_flag;
$redis = $this -> redis;
$isLock = $redis -> setnx($key, $value);
$redis -> expire($key,$timeout);
if ($isLock) {
if ($redis -> get($key) == $value) {
// 执行内部代码
$callback();
// 释放锁
$this -> del_lock();
break;//执行成功删除key并跳出循环
}
} else {
$count++;
if ($count > $overCount){
$errCallback();
break;
}
sleep(1); //睡眠,降低抢锁频率
}
} while(!$isLock);
}
/**
* 删除锁
*/
public function del_lock(){
$this -> redis -> del($this -> lock_name);
}
}
参考教程