Redis实现缓存点赞思路

本文介绍了如何使用TP6框架、think-queue消息队列和Middleware在直播平台应用中,通过Redis实现点赞功能的实时缓存,并定时同步至MySQL数据库,确保数据持久性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Redis实现缓存点赞思路

纵所周知,优酷和抖音这类直播平台都会有点击屏幕就点赞的功能,这类不太重要的数据,交给redis处理是最优的,定时存入MySQL数据库中,就可以实现数据的持久化。
本博基于tp6框架技术,结合think-queue消息队列,middleware中间件。
实现redis向mysql点赞的同步。

本博使用消息队列:composer require topthink/think-queue

一、controller层

主要是将前端的数据存到redis之中,用redis的哈希表储存;
redis的哈希表存储键值对:cache()->hset(‘v5_like_num’, ‘user_1’,0);
redis的哈希表获取键值对:cache()->hget(‘v5_like_num’, ‘user_1’);
redis的哈希表步进value值:cache()->hincrby(‘v5_like_num’, ‘user_1’, ‘步进的整数’);

namespace app\v5\controller;

use app\BaseController;
use think\facade\Db;

/**
 * redis点赞
 */
class Redis extends BaseController
{
    /**
     * 显示视图:这里的视图只是为了方便展示
     */
    public function index()
    {
        $data['res'] = Db::table('v5_like_num')->select()->toArray();
        $data['redis_like_num'] = cache()->hget('v5_like_num', 'user_1');
        // halt($data);
        return view('redis/index', $data);
    }

    /**
     * 添加数据到redis接口
     */
    public function add()
    {
        $step = (int)request()->post('step', 0);
        //添加redis
        cache()->hincrby('v5_like_num', 'user_1', $step);
        // dump($step);
        // dump(cache()->hget('v5_like_num', 'user_1'));
    }
}

视图层参考:view/redis/index
源码:https://github.com/xiaopacairq/tpAdmin/blob/main/app/v5/view/redis/index.php
核心代码如下:

// 点赞攒值,每3秒缓存到redis一次
setInterval(function() {
            $.post('/v5/redis/add', {
                step,
            }, function(res) {
                step = 0;
            }, '')
        }, 3000)

二、数据库层

  1. Mysql数据库
    在这里插入图片描述
  2. Reids数据库
    在这里插入图片描述

三、Job工作类

  1. queue的配置选项config/queue.php,默认是sync同步执行,可修改为redis缓存
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: yunwuxin <448901948@qq.com>
// +----------------------------------------------------------------------

return [
    'default'     => 'redis',
    'connections' => [
        'sync'     => [
            'type' => 'sync',
        ],
        'database' => [
            'type'       => 'database',
            'queue'      => 'default',
            'table'      => 'jobs',
            'connection' => null,
        ],
        'redis'    => [
            'type'       => 'redis',
            'queue'      => 'default',
            'host'       => '127.0.0.1',
            'port'       => 6379,
            'password'   => '',
            'select'     => 0,
            'timeout'    => 0,
            'persistent' => false,
        ],
    ],
    'failed'      => [
        'type'  => 'none',
        'table' => 'failed_jobs',
    ],
];

编写Job工作类,可参考文档:https://packagist.org/packages/topthink/think-queue
具体工作内容:将redis缓存的数据定时5秒存入到mysql中

<?php

namespace app\job;

use think\queue\Job;
use think\facade\Db;

class Job1
{

    public function fire(Job $job, $data)
    {
        $isJob = $this->redisToMysql($data);
        if ($isJob) {
            $job->delete();
        } else {
            //通过这个方法可以检查这个任务已经重试了几次了
            $attempts = $job->attempts();
            if ($attempts == 0 || $attempts == 1) {
                // 重新发布这个任务
                $job->release(5); //$delay为延迟时间,延迟5S后继续执行
            } elseif ($attempts == 2) {
                $job->release(5); // 延迟5S后继续执行
            }
        }
    }

    public function failed($data)
    {

        // ...任务达到最大重试次数后,失败了
    }

    private function redisToMysql($number)
    {
		//将redis数据存入到mysql数据库当中
        $isAdd = Db::table('v5_like_num')
            ->where('title', '文章1')
            ->inc('like_num', $number)
            ->update();
        if ($isAdd) {
            return true;
        } else {
            return false;
        }
    }
}

四、middleware中间件

中间件工作:定时执行队列 Queue::later(5, 'Job1@fire', $number, 'jobdemo');
队列工作时,需要在命令行执行:php think queue:work --queue jobdemo

  1. 注册中间件
<?php
// 全局中间件定义文件
return [
    // 全局请求缓存
    // \think\middleware\CheckRequestCache::class,
    // 多语言加载
    // \think\middleware\LoadLangPack::class,
    // Session初始化
    \think\middleware\SessionInit::class,
	// 初始化消息中间件
    app\v5\middleware\RedisToMysql::class,
];
  1. 实现中间件
<?php

namespace app\v5\middleware;

use think\facade\Queue;

class RedisToMysql
{
    public function handle($request, \Closure $next)
    {
        $number = (int)cache()->hget('v5_like_num', 'user_1');
        //执行队列
        $isPushed = Queue::later(5, 'Job1@fire', $number, 'jobdemo');
        if ($isPushed) {
            cache()->hset('v5_like_num', 'user_1', 0); //队列执行成功,让点赞步进值为0
        }
        return $next($request);
    }
}

执行php think queue:work --queue jobdemo,只有出现processed状态,才算队列执行成功,一直是processing状态,大概率是Job工作类写错了!
在这里插入图片描述
实现结果是:

  • 前端点赞,3秒后传入到后端接口
  • 后端接口将前端的点赞集合缓存到redis
  • 中间件每隔5秒自动将redis的数据缓存到mysql,并清空redis缓存

在这里插入图片描述

本博到此结束,thinkphp,以及勤劳的自己!

### Java Redis 实现量统计 #### 使用场景说明 在设计据模型时,将详情存储到 Redis 中而没有直接存储到数据库中,通常是出于性能、响应速度和并发处理的考虑。然而,这种做法也带来了据丢失的风险[^1]。 #### 设计思路 为了提高效率并减少延迟,在实现功能时可以利用 Redis 的高性能特性。由于 Redis 是基于内存的据结构存储系统,因此其读写速度远超传统的关系型数据库。这使得 Redis 成为缓存层的理想选择,特别是在高频率访问的应用程序组件上,比如社交平台上的按钮击事件记录。 #### 技术选型与工具介绍 对于 Java 应用来说,`Spring Data Redis` 提供了一个强大的 API 接口用于连接和操作 Redis 数据库。其中 `RedisTemplate` 类提供了多种便捷的方法来进行键值对管理,包括但不限于字符串、哈希表、集合等基本类型的增删改查操作。特别是它的 `execute()` 方法作为核心接口之一被广泛应用于自定义命令执行逻辑之中[^2]。 #### 示例代码展示 下面是一个简单的例子展示了如何使用 Spring Boot 和 Jedis 客户端来完成一次完整的流程: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; @Service public class LikeService { private final StringRedisTemplate stringRedisTemplate; @Autowired public LikeService(StringRedisTemplate stringRedisTemplate) { this.stringRedisTemplate = stringRedisTemplate; } /** * 对指定对象进行/取消. * * @param objectId 被的对象 ID * @param userId 用户 ID */ public boolean toggleLike(final String objectId, final long userId) { // 构建唯一的 key 名字 String likeKey = "like:" + objectId; Boolean exists = stringRedisTemplate.opsForSet().isMember(likeKey, String.valueOf(userId)); if (exists != null && !exists) { // 如果不存在,则添加至 set 并返回 true 表示成功 stringRedisTemplate.opsForSet().add(likeKey, String.valueOf(userId)); return true; } else { // 否则移除该成员表示取消,并返回 false stringRedisTemplate.opsForSet().remove(likeKey, String.valueOf(userId)); return false; } } /** * 获取某个对象总的. * * @param objectId 被的对象 ID * @return 总共获得多少次 */ public long getLikesCount(final String objectId) { String likeKey = "like:" + objectId; return stringRedisTemplate.opsForSet().size(likeKey); } } ``` 上述代码片段实现了两个主要的功能函:一个是用来切换用户的状态;另一个是用来获取特定目标收到的所有目。这里采用了 Set 结构保存每一个唯一用户对该项做出的动作,从而避免重复计算同一个用户的多次相同行为。 #### 处理持久化问题 考虑到 Redis 可能会遇到重启或其他原因造成临时性的据遗失情况,建议定期同步重要的业务据回 MySQL 或者其他关系型数据库内做长期保存。可以通过定时任务的方式批量导出增量更新部分的据条目,确保即使发生意外也不会影响整体系统的正常运作[^4]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小趴菜RQS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值