Redis 中的统计数据最终要写回到数据库中,这样才能保证数据的一致性。
思考?哪些数据需要同步?,是否一次性将所有数据同步到MySQL?
解决方案:
- 使用 Redis 的 ZSet,ZSet 可以设置分数,根据分数范围查询数据
- 当文章被浏览,置顶等操作时,将该文章添加到ZSet中,同时增加分数
- 使用定时任务,每次从 ZSet 中查询给定分数范围的数据,将其同步到数据库中。
- 同步完成删除该范围的数据,即清除 ZSet 中已同步的数据
统计文章分数
打开模块:trip-article-server,找到:StrategyServiceImpl,修改statDataIncr
方法,增加统计文章分数方法
RedisService 中加入该方法,当文章不存在时会新增一个
/** * 针对 zset 成员进行增加分数 * * @param prefix 前缀 * @param increment 增加的值 * @param member 成员 */ public void zsetIncrement(KeyPrefix prefix, double increment, Object member, String... suffix) { redisTemplate.opsForZSet().incrementScore(prefix.fullKey(suffix), member, increment); }
|
StrategyServiceImpl
private void statDataIncr(String hashKey, Long sid) { redisService.hashIncrement(StrategyRedisKeyPrefix.STRATEGIES_STAT_DATA_MAP, hashKey, 1, sid + ""); redisService.zsetIncrement(StrategyRedisKeyPrefix.STRATEGIES_STAT_DATA_MAP, 1, sid + ""); }
|
数据同步定时任务
打开模块:trip-data-server,在com.swx.data.job
包下创建 StrategyStatDataPersistenceJob
StrategyStatDataPersistenceJob
@Slf4j @Component public class StrategyStatDataPersistenceJob {
private final RedisService redisService; private final StrategyService strategyService;
public StrategyStatDataPersistenceJob(RedisService redisService, StrategyService strategyService) { this.redisService = redisService; this.strategyService = strategyService; }
@Scheduled(cron = "0 */10 * * * *") public void task() { log.info("[攻略数据持久化] ---------------- 持久化数据开始 ----------------"); Set<Integer> list = redisService.zsetRerange(StrategyRedisKeyPrefix.STRATEGIES_STAT_COUNT_RANK_ZSET, 0, Integer.MAX_VALUE); if (list != null && !list.isEmpty()) { List<Strategy> updateList = new ArrayList<>(); for (Integer id : list) { Map<String, Object> map = redisService.getCacheMap(StrategyRedisKeyPrefix.STRATEGIES_STAT_DATA_MAP.fullKey(id + "")); Strategy strategy = new Strategy(); strategy.setViewnum((Integer) map.get("viewnum")); strategy.setReplynum((Integer) map.get("replynum")); strategy.setFavornum((Integer) map.get("favornum")); strategy.setSharenum((Integer) map.get("sharenum")); strategy.setThumbsupnum((Integer) map.get("thumbsupnum")); strategy.setId(id.longValue()); updateList.add(strategy); } strategyService.updateBatchById(updateList); redisService.zsetRemoveRange(StrategyRedisKeyPrefix.STRATEGIES_STAT_COUNT_RANK_ZSET, 0, Integer.MAX_VALUE); log.info("[攻略数据持久化] 持久化数量:{}", list.size()); } log.info("[攻略数据持久化] ---------------- 持久化数据结束 ----------------"); } }
|
这里感觉有点问题,如果在同步时,有用户更新了文章的分数,那么按照范围删除数据不导致不同步吧?