thinkphp6 使用redis的PIPELINE处理数据并大量更新数据

需求:对大量学生进行各类成绩进行排名

原理:把成绩通过redis的PIPELINE分批添加到有序集合,取出后更新到临时表,再一次性更新到大表数据避免大表锁过长时间

直接上代码:

public static function countRank($paperId)
    {
        $redis = Cache::store('redis')->handler();
        $redisSelect = Config::get('cache.stores.redis.select');
        $redis->select($redisSelect);
        $key = Config::get('cache.stores.redis.prefix') . 'paper:rank:' . $paperId;

        $studentScore = PaperRankModel::where(['paper_id' => $paperId])->column('id,total_score');
        if (empty($studentScore)) {
            return true;
        }
        
        //这里可以一次打包1k~2k条命令,视实际情况而定  我懒得写了
		$pipe = $redis->pipeline();
        foreach ($studentScore as $v) {
            $pipe->zAdd($key, $v['total_score'], $v['id']);
        }
        $pipe->exec();

        $data = $newRank = [];
        $i = $oldGradeRank = 1;
        $rank = $redis->zRevRange($key, 0, -1, true);
        foreach ($rank as $k => $v) {
            $newRank[] = ['pk' => $k, 'total_score' => $v];
        }
        foreach ($newRank as $k => $v) {
            if ($k == 0 || $v['total_score'] != $newRank[$k - 1]['total_score']) {
                $gradeRank = $i;
                $oldGradeRank = $i;
            } else {
                $gradeRank = $oldGradeRank;
            }
            $data[] = ['paper_id' => $paperInfo['id'], 'pk' => $v['pk'], 'rank' => $gradeRank];
            $i++;
        }

        PaperRankTmpModel::insertAll($data);
        PaperRankModel::alias('rank')->join('paper_rank_tmp tmp', 'rank.id = tmp.pk')->where(['rank.paper_id' => $paperId])->update(['rank.grade_rank' => Db::raw('tmp.rank')]);

        PaperRankTmpModel::where(['paper_id' => $paperId])->delete();
        $redis->del($key);
        $studentScore = null;
        return true;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值