PHP 實現一個可用的redis 事務鎖, 解決併發問題

 

調用代碼

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章