我正在用PHP编写彩票程序,因为对此程序会有大量的并发请求,每个奖品的数量有限,在此示例中为10。我不希望看到任何奖金超过存货。所以我将整个逻辑放在Redis的事务中(我使用predis(https://github.com/nrk/predis)作为我的PHP redis客户端),但是在对该程序的请求超过10次后,我发现数据库中有10条以上的记录我听不懂有谁知道原因吗?非常感谢您的解释,谢谢!

这是我的PHP代码:

$this->load->model('Lottery_model');
$money = $this->_get_lottery();//which prize do you get
if($money > 0){
    $key = $this->_get_sum_key($money);
    $dbmodel = $this->Lottery_model;
    // Executes a transaction inside the given callable block:
    $responses = $redis->transaction(function ($tx) use ($key, $money, $dbmodel){
        $qty = intval($tx->get($key));
        if($qty < 10){
            //not exceed the stock limit
            $dbmodel->add($customer, $money);  // insert record into db
            $tx->incr($key);
        }else{
            log_message('debug', $money . ' dollar exceed the limit');
        }
    });
    }else{
        log_message('debug', 'you are fail');
    }

阅读有关Redis交易的文档后,我知道上述代码的使用是完全错误的。然后我使用乐观锁定和检查设置将其修改为以下版本。
$options = array(
    'cas' => true,      // Initialize with support for CAS operations
    'watch' => $key,    // Key that needs to be WATCHed to detect changes
    'retry' => 3,
);
try{
    $responses = $redis->transaction($options, function ($tx) use ($key, $money, $username, $dbmodel, &$qty){
    $qty = intval($tx->get($key));
    if($qty < 10){
        $tx->multi();
        $tx->incr($key);
        $dbmodel->add($username, $money);// insert into mysql db
    }else{
        log_message('debug', $money . ' dollar exceed the limit');
    }
});
}catch(PredisException $e){
    log_message('debug', 'redis transaction failed');
}

但是问题是数据库中的记录数超过了奖品的限制,Redis中保存的总数不会。解决此类问题的常用解决方案是什么?在这种情况下我必须锁定INNodb表吗?

最佳答案

您需要了解Redis事务的工作原理-简而言之,所有进行事务的命令都由客户端(在您的情况下为predis)缓冲,然后立即发送到服务器。您的代码尝试在执行事务之前使用读取请求的结果(get)。请参阅文档以获取更多详细信息:https://redis.io/topics/transactions

要么在事务外部读取qty,然后使用 WATCH 防止竞争性更新,要么将此逻辑整体移到Lua脚本中。

关于php - 为什么在Redis事务中无法获取缓存的数据?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42643380/

10-11 22:20
查看更多