redis中的increment()方法遇到的问题记录

问题引出
1、项目中需要使用redis对key进行有效时长设置
2、在对该key进行有效时长设置时同时需要原子性的增加该key对应的值
3、每次获取当前key对应的value进行大小判断从而进行业务逻辑处理
产生的问题
1、使用set方法直接设置key的有效时长时,该操作将会重置key的有效时长
2、使用increment()方法时该方法会在key不存在时redis会自动建立key并对该key值进行加一操作,但是该新生成的key将不会有过期时间
解决方法
1、对需要set到redis中的key设置一个初始值1并设置该key的有效时长
2、使用increment()方法进行增加后,该方法会返回增加后的值,该值一般情况下一定是大于1的
3、判断如果当前key的值等于1时就说明存在在increment()方法执行时,当前key刚好过期。当前的key是由redis自动执行的加一操作,但是该key是不具备过期时长设置的。此时需要对该key重新设置key的时长

### SpringBoot 和 Redis 实现文章浏览量统计 为了实现文章浏览量的记录功能,可以借助 Redis 的 HyperLogLog 数据结构来去重并计算独立访客的数量(UV),同时也可以简单地使用字符串类型的键值对来累加总访问次数(PV)。以下是具体的实现方式: #### 1. 使用 HyperLogLog 记录 UV Redis 提供了 `PFADD` 命令用于向 HyperLogLog 中添加元素,而 `PFCOUNT` 则用来获取当前集合中的近似唯一值数量。这种方式非常适合处理高并发场景下的 UV 统计。 ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; @Service public class ArticleService { @Autowired private StringRedisTemplate redisTemplate; public void recordArticleView(String articleId, String userIp) { // 定义 key,例如:"article:uv:{articleId}" String uvKey = "article:uv:" + articleId; // 添加 IP 地址到 HyperLogLog 结构中 redisTemplate.opsForHyperLogLog().add(uvKey, userIp); // 更新 PV (Page View),定义 key 如:"article:pv:{articleId}" String pvKey = "article:pv:" + articleId; redisTemplate.opsForValue().increment(pvKey); // 自增操作 } public long getUniqueViews(String articleId) { // 获取 UV 数量 String uvKey = "article:uv:" + articleId; return redisTemplate.opsForHyperLogLog().size(uvKey); } public long getTotalViews(String articleId) { // 获取 PV 总数 String pvKey = "article:pv:" + articleId; Object totalViewsObj = redisTemplate.opsForValue().get(pvKey); if (totalViewsObj != null && !"".equals(totalViewsObj.toString())) { return Long.parseLong(totalViewsObj.toString()); } return 0L; // 如果不存在返回默认值 0 } } ``` 上述代码实现了两个主要的功能: - **recordArticleView**: 每次有新的页面访问时调用此方法,传入文章 ID (`articleId`) 和用户 IP (`userIp`) 来记录一次访问行为。 - **getUniqueViews**: 返回指定文章的独立访客数量(UV)[^1]。 - **getTotalViews**: 返回指定文章的总访问次数(PV)。 #### 2. 处理定时任务同步数据至数据库 为了避免频繁读写数据库带来的性能瓶颈,可以在夜间或其他低峰期通过定时任务将 Redis 中的数据持久化到关系型数据库中。 ```java import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component public class DataSyncTask { @Scheduled(cron = "0 0 2 * * ?") // 每天凌晨两点执行 public void syncDataToDatabase() { // 查询所有文章的 PV 和 UV 并保存到数据库 List<String> allArticles = getAllArticleIdsFromRedis(); // 获取所有文章ID列表 for (String articleId : allArticles) { long pv = articleService.getTotalViews(articleId); long uv = articleService.getUniqueViews(articleId); saveToDatabase(articleId, pv, uv); // 调用 DAO 方法保存到 DB } } private List<String> getAllArticleIdsFromRedis() { Set<String> keys = redisTemplate.keys("article:*"); return new ArrayList<>(keys.stream() .map(k -> k.replace("article:", "")) .collect(Collectors.toSet())); } private void saveToDatabase(String articleId, long pv, long uv) { // TODO: 实现具体逻辑,将数据插入或更新到数据库表中 } } ``` 这段代码展示了如何设置一个定时器,在每天固定时间触发并将 Redis 中的文章浏览统计数据批量导入数据库。 #### 3. 缓存优化与异常保护 考虑到实际生产环境可能会遇到诸如缓存穿透、缓存雪崩等问题,因此还需要采取一些额外措施保障系统的稳定性。比如可以通过为每个缓存 Key 设置带有随机偏移量的有效期限来减少集中过期的风险;另外还可以引入熔断机制防止突发流量冲击下游服务[^2]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值