从头开始学Redisson--------分布式集合之列表(RList)

x33g5p2x  于2021-12-28 转载在 其他  
字(3.5k)|赞(0)|评价(0)|浏览(698)

一、分布式集合List

      基于Redis的Redisson分布式列表(List)结构的RList Java对象实现了java.util.List接口。简直太方便了。遥想当初为了用Redis的List类型,得做如下的代码  StringRedisTemplate.opsForList()得到操作List集合的对象;

      Redisson的RList相当于一个Redis的List类型的数据结构。因为其的底层实现就是Redis的List,所以其核心使用心法就是用于存储一对多的热点数据。

      从我自己的公司角度的业务上来看。可以使用Redis的List来做例如 "班级-学生"、"学院-专业"、"年级-学院"等一对多的业务场景。因此,对于Redis的List这种数据结构而言,只要牢牢记住,当出现一对多的场景时,可以考虑使用List这种Redis数据结构来做热点数据的缓存。

技术参考文档:
RList<SomeObject> list = redisson.getList("anyList");
list.add(new SomeObject());
list.get(0);
list.remove(new SomeObject());

二、实战

       现在的需求是记录用户的操作日志。数据库里存放两个字段,一个是用户账号,一个是操作时间。

package com.tyzhou.redisson.service;

import com.tyzhou.Constant;
import com.tyzhou.redisson.mapper.LogMapper;
import com.tyzhou.redisson.model.LogDO;
import com.tyzhou.utils.CollectionUtils;
import org.redisson.api.RList;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * Redisson List 作为访问记录日志缓存
 *
 * @author zhoutianyu
 * @date 2020/3/19
 * @time 19:19
 */
@Service
public class LogService {

    @Autowired
    private LogMapper logMapper;

    @Autowired
    private RedissonClient redisson;

    public void insertLog(String userAccount) {
        LogDO log = new LogDO(userAccount);
        //插入日志到数据库
        logMapper.insertLog(log);
        if (log.getId() > 0) {
            //同时从Redis获取日志缓存,将本次日志加入进去
            RList<LogDO> logList = redisson.getList(Constant.REDISSON_LOG);
            logList.add(log);
        }
    }

    //通过账号查询这个人的操作记录缓存
    public List<LogDO> getLogCache(String userAccount) {
        //从Redis缓存中取数据
        RList<LogDO> logList = redisson.getList(Constant.REDISSON_LOG);
        if (CollectionUtils.isNotEmpty(logList)) {
            return logList;
        }
        //如果缓存中没有数据,则从数据库的日志表中查询操作日志
        return logMapper.selectAll(userAccount);
    }

}

package com.tyzhou.redisson.model;

import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@NoArgsConstructor
public class LogDO {

    private Integer id;
    private String userAccount;
    private Date operationTime;

    public LogDO(String userAccount) {
        this.userAccount = userAccount;
        this.operationTime = new Date();
    }
}

      为了保证日志与数据库中一致,所以还要添加一个定时任务,定时将日志记录加入到缓存。

package com.tyzhou.redisson.schedule;

import com.tyzhou.Constant;
import com.tyzhou.redisson.mapper.LogMapper;
import com.tyzhou.redisson.model.LogDO;
import com.tyzhou.utils.CollectionUtils;
import org.redisson.api.RList;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
@EnableScheduling
@EnableAsync
public class LogSchedule {

    private static final Logger LOGGER = LoggerFactory.getLogger(LogSchedule.class);

    @Autowired
    private LogMapper logMapper;

    @Autowired
    private RedissonClient redisClient;

    //10分钟同步一次(开发测试可增加频率)
    @Scheduled(cron = "* */10 * * * ?")
    @Async
    public void selectLogCache() {
        LOGGER.info("同步日志缓存");
        RList<LogDO> logCacheList = redisClient.getList(Constant.REDISSON_LOG);
        //清空所有
        logCacheList.delete();

        List<LogDO> logList = logMapper.selectAll("");
        if(CollectionUtils.isNotEmpty(logList)){
            logCacheList.addAll(logList);
        }
    }
}

三、实现效果

      发送几次请求,参数是某个学生。在数据库里会记录这个学生的操作日志,并将缓存日志Redisson的某个List中。

      再发送查询日志的请求,先从Redisson的某个List中拿数据。如果没拿到数据,才查询一次数据库。

      为了保证数据库与缓存一致,有定时任务按照一定的频率,把DB中的操作日志全部查询出来,放入Redisson的某个List中。因此下次查询的时候就可以先走缓存,而不是查询DB,从而达到为DB减少负载的目的。

相关文章