欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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);
    }
}

参考教程

http://ukagaka.github.io/php/2017/09/21/redisLock.html