springboot+redis+mysql+quartz-通过Java操作jedis的scan命令获取缓存数据定时更新数据库

一、重点

代码讲解:5-点赞功能-定时持久化到数据库-pipeline+lua-优化ByScan_哔哩哔哩_bilibili

https://www.bilibili.com/video/BV1Gs4y1676q

代码:

blogLike_schedule/like05 · xin麒/XinQiUtilsOrDemo - 码云 - 开源中国 (gitee.com)

https://gitee.com/flowers-bloom-is-the-sea/XinQiUtilsOrDemo/tree/master/blogLike_schedule/like05

数据库表:
blogLike_schedule · xin麒/XinQiUtilsOrDemo - 码云 - 开源中国 (gitee.com)

这篇文章是根据上一篇文章:(108条消息) springboot+redis+mysql+quartz-通过Java操作redis的KEYS*命令获取缓存数据定时更新数据库_xin麒的博客-CSDN博客

https://blog.csdn.net/ws_please/article/details/131621669

进行的优化。

二、核心过程

1、重要依赖:

        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>

2、配置jedis:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import org.springframework.beans.factory.annotation.Value;
@Configuration
public class JedisConfig {
 
    private Logger logger = LoggerFactory.getLogger(JedisConfig.class);
 
    @Value("${spring.redis.host}")
    private String host;
 
    @Value("${spring.redis.port}")
    private int port;
 
    @Value("${spring.redis.password}")
    private String password;
    @Value("${spring.redis.timeout}")
    private int timeout;
   
    @Value("${spring.redis.jedis.pool.max-active}")
    private int maxActive;
 
    @Value("${spring.redis.jedis.pool.max-idle}")
    private int maxIdle;
 
    @Value("${spring.redis.jedis.pool.min-idle}")
    private int minIdle;
 
    @Bean
    public JedisPool jedisPool(){
        JedisPoolConfig jedisPoolConfig=new JedisPoolConfig();
        jedisPoolConfig.setMaxIdle(maxIdle);
        jedisPoolConfig.setMinIdle(minIdle);
        jedisPoolConfig.setMaxTotal(maxActive);
 
        JedisPool jedisPool=new JedisPool(jedisPoolConfig,host,port,timeout,password);
 
        logger.info("JedisPool连接成功:"+host+"\t"+port);
 
        return jedisPool;
    }
}

定时板块就看这篇吧:

https://blog.csdn.net/ws_please/article/details/131621669

3、这里大体上的内容和上一篇文章差不多的,就是从缓存获取数据的方法换成了scan:

//这里就执行所有博客的likeList入库吧
    @Override
    public void updateAllLikeListToDatabase() {
        String prefix = "BLOG_LIKED_KEY";
//        Set keys = getAllRedisKeyByKeys(prefix);//这个不行!
        Set<String> keys = getAllRedisKeyByScanThroughMatch(prefix);

        if (keys == null || keys.size() == 0) return;
        for (String key : keys) {
            Map<String, String> map = queryAllBlogLikesUserIdWithScoresByRedisKey(key);
            //get blogId,,这个blogId是在后半段的。
            Long blogId = Long.parseLong(key.substring(prefix.length(), key.length()));

            durableToDatabaseByBlogIdAndMap(map,blogId);

        }

    }

先通过jedis的scan方法模糊匹配出所有博客id的键

//通过scan来模糊匹配
public Set<String> getAllRedisKeyByScanThroughMatch(String prefix) {//找不到stringRedisTemplate对Zset里键值对扫描的资料
    Jedis jedis = null;
    Set<String> blogLikeList = new HashSet<>();
    ScanParams scanParams = new ScanParams();
    try {
        jedis = jedisPool.getResource();
        String cursor = "0";


        do {
            // 扫描并获取一部分key
            ScanResult<String> result = jedis.scan(cursor, scanParams.match(prefix.concat("*")));
            // 记录cursor
            cursor = result.getCursor();
            List<String> list = result.getResult();
            if (list == null || list.isEmpty()) {
                break;
            }

            // 遍历
            for (String key : list) {
                // 判断key的类型
                log.debug("key is {}", key);//这里可以看到有哪些key
                //符合就要,不符合就不要
                blogLikeList.add(key);
            }

        } while (!cursor.equals("0"));
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (jedis != null) jedis.close();
    }
    return blogLikeList;
}

再通过stringRedisTemplate得到某篇博客的所有点赞信息:

private Map<String, String> queryAllBlogLikesUserIdWithScoresByRedisKey(String key) {
    Set<String> stringUserIdList = stringRedisTemplate.opsForZSet().range(key, 0, -1);

    if (stringUserIdList == null || stringUserIdList.size() == 0) return new HashMap<>();

    List<String> ids = stringUserIdList.stream().map(String::valueOf).collect(Collectors.toList());
    HashMap<String, String> userIdWithTime = new HashMap<>();
    for (String userId : stringUserIdList) {//暂时找不到可以直接返回List的api
        String score = stringRedisTemplate.opsForZSet().score(key, userId).toString();
        userIdWithTime.put(userId, score);
    }
    return userIdWithTime;
}

其他和https://blog.csdn.net/ws_please/article/details/131621669基本一致。

三、其他

还可以继续优化,比如使用pipeline技术:

(108条消息) springboot+redis+mysql+quartz-通过Java操作jedis使用pipeline获取缓存数据定时更新数据库_xin麒的博客-CSDN博客

https://blog.csdn.net/ws_please/article/details/131623267

或者说用lua脚本也可以:

(108条消息) springboot+redis+mysql+quartz-通过Java操作jedis定时使用lua脚本获取缓存数据并更新数据库_xin麒的博客-CSDN博客

https://blog.csdn.net/ws_please/article/details/131623224

现在是2023-07-01,不得不吐槽stringRedisTemplate,对于scan扫描好像stringRedisTemplate的方法是找不到的,jedis的参考资料非常丰富,全网几乎搜不到stringRedisTemplate对zset数据的scan操作信息,官网也很少资料(可能没细看),笑死,所以后面就用jedis来实现了。

其他类似的文章:

(108条消息) springboot+redis+mysql+quartz-通过Java操作redis的KEYS*命令获取缓存数据定时更新数据库_xin麒的博客-CSDN博客

(108条消息) springboot+redis+mysql+quartz-通过Java操作jedis定时使用lua脚本获取缓存数据并更新数据库_xin麒的博客-CSDN博客

(108条消息) lua脚本获取table类型-Java使用lua脚本操作redis获取zset元素的集合_xin麒的博客-CSDN博客

(108条消息) springboot+redis+mysql+quartz-通过Java操作jedis使用pipeline获取缓存数据定时更新数据库_xin麒的博客-CSDN博客

(108条消息) springboot+redis+mysql+quartz-通过Java操作jedis的scan命令获取缓存数据定时更新数据库_xin麒的博客-CSDN博客

你可能感兴趣的:(java,数据库,spring,boot,redis,定时任务)