利用Redis实现延时任务

今天碰到一个需求是:将社区首页推荐中用户2小时前浏览或互动过的内容删除,需要用Redis实现延时任务来解决。
参考: 如何用 Redis 实现延时任务?

数据库:

====为用户的推荐数据V5(kid_recommend_data_for_user_v5)
id - ID
user_id - 用户ID
object_type - 对象类型(0笔记/1日志/3回答)
object_id - 对象ID
create_time - 创建时间

====浏览或互动相关逻辑SQL:在ConsoleCalcRecommendDataForUserV5的“计算为用户的推荐数据V5”方法中
    (
      p.object_type=0
      AND NOT EXISTS(SELECT * FROM kid_view_log WHERE user_id={0} AND object_type=16 AND object_id=p.object_id)
      AND NOT EXISTS(SELECT * FROM rec_vote WHERE user_id={0} AND object_type=23 AND object_id=p.object_id AND vote=1)
      AND NOT EXISTS(SELECT * FROM rec_booklist_favorite WHERE type=10 AND booklist_id=p.object_id AND user_id={0} AND favorite_flag=1)
      AND NOT EXISTS(SELECT * FROM rec_comment FORCE INDEX(idx2_user_id) WHERE user_id={0} AND object_type=23 AND object_id=p.object_id)
    ) OR
    (
      p.object_type=1
      AND NOT EXISTS(SELECT * FROM kid_view_log WHERE user_id={0} AND object_type=2 AND object_id=p.object_id)
      AND NOT EXISTS(SELECT * FROM rec_experience_vote WHERE experiences_id=p.object_id AND user_id={0})
      AND NOT EXISTS(SELECT * FROM rec_experience_favorites WHERE experiences_id=p.object_id AND user_id={0})
      AND NOT EXISTS(SELECT * FROM rec_experiences_reply WHERE experiences_id=p.object_id AND user_id={0})
    ) OR
    (
      p.object_type=3
      AND NOT EXISTS(SELECT * FROM kid_view_log WHERE user_id={0} AND object_type=1 AND object_id=p.object_id)
      AND NOT EXISTS(SELECT * FROM rec_vote WHERE user_id={0} AND object_type=20 AND object_id=p.object_id AND vote=1)
      AND NOT EXISTS(SELECT * FROM rec_booklist_favorite WHERE type=5 AND booklist_id=p.object_id AND user_id={0} AND favorite_flag=1)
      AND NOT EXISTS(SELECT * FROM rec_comment FORCE INDEX(idx2_user_id) WHERE user_id={0} AND object_type=20 AND object_id=p.object_id)
    )

步骤:
1、编写存储过程delete_recommend_content; 参数:(user_id integer,object_type integer,object_id integer)

BEGIN
    DECLARE v_json VARCHAR(4000);
    DECLARE v_redis_ret INT;
    DECLARE v_timestamp BIGINT;

    SET v_json=CONCAT(user_id, ',', object_type, ',', object_id);
    SET v_timestamp=UNIX_TIMESTAMP(DATE_ADD(NOW(),INTERVAL 2 HOUR));
    SET v_redis_ret=redis_command_v2('eval', CONCAT('redis.call(', '''ZADD''', ',', '''DeleteRecommendContent''', ',', v_timestamp, ',', '''', v_json, '''', ')'), '0');
END

2、触发器

kid_view_log
错误:一直以为是条件错误,结果是传的值不正确,还是没有正确理解需求以及表结构。
BEGIN
  IF new.object_type=16 OR new.object_type=2 OR new.object_type=1 THEN
    call delete_recommend_content(new.user_id, new.object_type, new.object_id);
  END IF;
END

正确:
BEGIN    
    IF (new.object_type=16) THEN
    call delete_recommend_content(new.user_id, 0, new.object_id);
  END IF;
    
    IF (new.object_type=2) THEN
    call delete_recommend_content(new.user_id, 1, new.object_id);
  END IF;

  IF (new.object_type=1) THEN
    call delete_recommend_content(new.user_id, 3, new.object_id);
  END IF;
END

rec_vote
BEGIN
  DECLARE v_ret INT;

  IF new.object_type=10 THEN
    SET v_ret = redis_command_v2('DEL', CONCAT('ReadRec:VoteUser:', new.object_id));
  END IF;

  IF (new.object_type=23 AND new.vote=1) THEN
    call delete_recommend_content(new.user_id, 0, new.object_id);
  END IF;

  IF (new.object_type=20 AND new.vote=1) THEN
    call delete_recommend_content(new.user_id, 3, new.object_id);
  END IF;
END

rec_experience_vote 
BEGIN
  DECLARE v_ret INT;

  SET v_ret = redis_command_v2('HDEL', 'ArticleVoteUser', CONCAT(new.experiences_id));

  CALL delete_recommend_content(new.user_id, 1, new.experiences_id);
END

rec_booklist_favorite 
BEGIN
  DECLARE v_ret INT;

  SET v_ret = redis_command_v2('LPUSH', 'mq:CalcUserFavoriteCount', CONCAT('{"pk":',new.user_id,'}'));

  IF new.type=5 THEN
    SET v_ret = redis_command_v2('LPUSH', 'mq:CalcFollowFeed', CONCAT(json_object('oper',new.user_id,'type',10,'contentType',3,'contentId',new.booklist_id)));
  ELSEIF new.type=10 THEN
    SET v_ret = redis_command_v2('LPUSH', 'mq:CalcFollowFeed', CONCAT(json_object('oper',new.user_id,'type',11,'contentType',0,'contentId',new.booklist_id)));
  ELSEIF new.type=2 THEN
    SET v_ret = redis_command_v2('LPUSH', 'mq:CalcFollowFeed', CONCAT(json_object('oper',new.user_id,'type',13,'contentType',6,'contentId',new.booklist_id)));
  ELSEIF new.type=8 THEN
    SET v_ret = redis_command_v2('LPUSH', 'mq:CalcFollowFeed', CONCAT(json_object('oper',new.user_id,'type',14,'contentType',7,'contentId',new.booklist_id)));
  ELSEIF new.type=1 THEN
    SET v_ret = redis_command_v2('LPUSH', 'mq:CalcFollowFeed', CONCAT(json_object('oper',new.user_id,'type',15,'contentType',15,'contentId',new.booklist_id)));
  END IF;
  
  IF (new.type=10 AND new.favorite_flag=1) THEN
    CALL delete_recommend_content(new.user_id, 0, new.booklist_id);
  END IF;

  IF (new.type=5 AND new.favorite_flag=1) THEN
    CALL delete_recommend_content(new.user_id, 3, new.booklist_id);
  END IF;
END

rec_experience_favorites 
BEGIN
  DECLARE v_ret INT;

  SET v_ret = redis_command_v2('LPUSH', 'mq:CalcUserFavoriteCount', CONCAT('{"pk":',new.user_id,'}'));
  SET v_ret = redis_command_v2('LPUSH', 'mq:CalcFollowFeed', CONCAT(json_object('oper',new.user_id,'type',8,'contentType',1,'contentId',new.experiences_id)));

  CALL delete_recommend_content(new.user_id, 1, new.experiences_id);
END

rec_comment 
BEGIN
  DECLARE v_ret INT;

  IF new.object_type=10 THEN
    SET v_ret = redis_command_v2('DEL', CONCAT('ReadRec:Comment:', new.object_id));
  END IF;

  SET v_ret = redis_command_v2('HDEL', 'LatestComment', CONCAT(new.object_type,'_',new.object_id));

  IF (new.object_type=23) THEN
    call delete_recommend_content(new.user_id, 0, new.object_id);
  END IF;

  IF (new.object_type=20) THEN
    call delete_recommend_content(new.user_id, 3, new.object_id);
  END IF;
END

rec_experiences_reply 
BEGIN
  DECLARE v_ret INT;

  SET v_ret = redis_command_v2('HDEL', 'ArticleReplyTopic', CONCAT(new.experiences_id));

  CALL delete_recommend_content(new.user_id, 1, new.experiences_id);
END

3、程序

package xhs.appApi.service;

import java.util.List;
import java.util.Set;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;

import redis.clients.jedis.Jedis;
import xhs.appApi.common.TextUtil;
import xhs.appApi.dao.CommonMapper;

public class DeleteRecommendContent {
    private static Logger logger = Logger.getLogger(DeleteRecommendContent.class);
    
    @Autowired
    private RedisService redisService;
    @Autowired
    private CommonMapper commonMapper;
    
    public void doJob() {
        if (!TextUtil.equals(System.getProperty("xhs.doJob"), "true")) return;
        
        Jedis jedis = redisService.getRedis();
        int userId, objectType, objectId;
        try {
            long timeMillis = System.currentTimeMillis()/1000;
            Set<String> set = jedis.zrangeByScore("DeleteRecommendContent", 0, timeMillis);
            for (String item : set) { // item="1,2,3"
                List<Integer> list = TextUtil.splitAsIntList(item); 
                userId = list.get(0);
                objectType = list.get(1);
                objectId = list.get(2);
                
                commonMapper.executeDelete(String.format("DELETE FROM kid_recommend_data_for_user_v5 WHERE user_id=%d AND object_type=%d AND object_id=%d", userId, objectType, objectId));
            }
            jedis.zremrangeByScore("DeleteRecommendContent", 0, timeMillis);
            
        } catch(Exception ex) {
            logger.error("doJob", ex);
        } finally {
            RedisService.closeRedis();
        }
    }
}

4、定时任务quarz配置

<bean id="job12" class="xhs.appApi.service.DeleteRecommendContent"/>
    <bean id="jobDetail_12" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"
        p:targetMethod="doJob"
        p:concurrent="false">
        <property name="targetObject"><ref bean="job12" /></property>  
    </bean>
    <bean id="cronTrigger_12" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"
        p:cronExpression="0 0/2 * * * ?">
        <property name="jobDetail"><ref bean="jobDetail_12" /></property>  
    </bean>
    
    <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">  
        <property name="triggers">  
            <list>  
                <ref bean="cronTrigger_1" />
                <ref bean="cronTrigger_2" />
                <ref bean="cronTrigger_3" />
                <ref bean="cronTrigger_4" />
                <ref bean="cronTrigger_5" />
                <ref bean="cronTrigger_6" />
                <ref bean="cronTrigger_7" />
                <ref bean="cronTrigger_8" />
                <ref bean="cronTrigger_9" />
                <ref bean="cronTrigger_10" />
                <ref bean="cronTrigger_11" />
                <ref bean="cronTrigger_12" />
            </list>  
        </property>  
    </bean>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值