首页 > 数据库 >Redis缓存数据和表数据一致性之延时双删策略

Redis缓存数据和表数据一致性之延时双删策略

时间:2023-09-12 09:12:07浏览次数:41  
标签:缓存 双删 Redis 和表 数据表 缓存数据 userInfo 延时

一、什么是 Redis 延时双删?

1、延迟双删策略是分布式系统中数据库存储和缓存数据保持一致性的常用策略,但它不是强一致。不管哪种方案,都无法绝对避免Redis存在脏数据的问题,只能减轻这个问题

2、因为双删策略执行的结果是把redis中保存的那条数据删除了,以后的查询就都会去查询数据库。经常修改的数据表不适合使用redis缓存

3、Redis适用的是读频率远远大于改频率的数据表,不适合改频率大于读频率的数据

二、为什么要使用延时双删?

先看下面两种脏数据情况:

1、情况一:先删除缓存数据,再update更新数据表

当请求1执行删除缓存数据后,还未来得及更新数据表或更新动作还未完成,此时请求2查询到数据表中仍然是更新之前的数据、并把脏数据写入了Redis缓存

2、情况二:先update更新数据表,再删除缓存数据

当请求1执行update更新数据表后,还未来得及删除缓存数据或删除缓存动作还未完成,此时请求2查询到Redis缓存中仍然是旧数据、并返回给前端

为了避免上述的两种情况数据不一致问题,就需要用到我们介绍的延时双闪策略:先删除缓存数据 》再执行update更新数据表 》最后(延时N秒)执行删除缓存

三、实现延时双删,示例:

1、有实现注释,代码如下

更新操作代码:

@Service
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {

@Resource
private RedisUtil redisUtil;
@Resource
private ScheduledExecutorService scheduledExecutorService;


/**
* <p>保存用户信息</p>
*
* @author hkl
* @date 2022/11/22
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void saveUserInfo(UserInfo userInfo) {
if(ObjectUtil.isNull(userInfo)){
return;
}

if(ObjectUtil.isNull(userInfo.getId())){
this.save(userInfo);
//Hash方式 start
redisUtil.putHash(RedisConstants.USER_INFO_HASH, String.valueOf(userInfo.getId()), userInfo);
//Hash方式 end
} else {
//测试Redis延时双删,Hash方式 start
//1、删除缓存数据
UserInfo getUserInfoResFirst = this.getById(userInfo.getId());
Optional.ofNullable(getUserInfoResFirst).ifPresent(obj -> {
redisUtil.deleteHash(RedisConstants.USER_INFO_HASH, String.valueOf(obj.getId()));
});

//2、更新数据表
this.updateById(userInfo);

//3、延时2秒后,再删除缓存数据
scheduledExecutorService.schedule(() -> {
Optional.ofNullable(getUserInfoResFirst).ifPresent(obj -> {
redisUtil.deleteHash(RedisConstants.USER_INFO_HASH, String.valueOf(obj.getId()));
});
}, 2, TimeUnit.SECONDS);
//测试Redis延时双删,Hash方式 end
}
}

}
查询操作代码:

@ApiOperation(value = "根据用户Id查询用户详情信息")
@ApiImplicitParam(value = "用户Id", name = "userId", required = true)
@GetMapping("/getUserInfoById")
public CommonResult<UserInfo> getUserInfoById(Integer userId) {
//Hash方式 start
Object userInfoObj = redisUtil.getHash(RedisConstants.USER_INFO_HASH, String.valueOf(userId));
if(ObjectUtil.isNotNull(userInfoObj)){
return success(userInfoObj);
}
UserInfo userInfo = userInfoService.getById(userId);
Optional.ofNullable(userInfo).ifPresent(obj -> {
redisUtil.putHash(RedisConstants.USER_INFO_HASH, String.valueOf(userId), obj);
});
//Hash方式 end
return success(userInfo);
}
说明:

以上就是实现缓存和数据表一致的延时双删策略Demo,经过测试可以保持数据一致

四、小结

1、使用延时双删策略是为了保持Redis缓存与数据表一致

2、第一次删除不再赘述,为了清除缓存中的旧数据

3、主要是第二次删除,第二次删除为什么要延时呢?延时1是为了等待更新数据表动作完成、2是为了等待更新数据表之前查询查到的旧数据写入缓存动作完成,最后再把写入缓存的旧数据删除

4、延时双删依然无法保证一致,只能减轻出现脏数据的情况,所以对一致性要求较高的数据尽量不要放入缓存

标签:缓存,双删,Redis,和表,数据表,缓存数据,userInfo,延时
From: https://www.cnblogs.com/jiaodaoniujava/p/17695095.html

相关文章

  • Redis.conf 详解
    一、NETWORK网络bind127.0.0.1#绑定的IPprotected-modeno#保护模式port6379#端口设置二、GENERAL通用daemonizeyes#以守护进程的方式运行,默认是no,我们需要自己开启为yespidfile/var/run/redis_6379.pid#如果是后台启动,我们需要指定一个pid文......
  • 我是如何用 redis 分布式锁来解决线上历史业务问题的
    近期发现,开发功能的时候发现了一个mq消费顺序错乱(历史遗留问题),导致业务异常的问题,看看我是如何解决的问题抛出首先,简单介绍一下情况:线上k8s有多个pod会去消费mq中的消息,可是生产者发送的消息是期望一定要有序去消费,此时要表达的是,例如生产者如果发送了3个通知消息,分......
  • Redis7 10大数据类型(概述)
    一、概述二、数据类型1、redis字符串(String)String(字符串)string是redis最基本的类型,一个key对应一个value。string类型是二进制安全的,意思是redis的string可以包含任何数据,比如jpg图片或者序列化的对象。string类型是Redis最基本的数据类型,一个redis中字符串value最多可以是51......
  • Redis为什么这么快?
    面试官:Redis为什么这么快?(qq.com)”因为它是内存数据库,不用往硬盘上写,所以快啊““基于内存实现”这个原因就不详细展开了哈,毕竟地球人都懂。空间换时间——SDS数据结构这里所说的空间为”内存空间“。Redis是用C语言写的,但它的String数据类型,并没有直接用C语言中的char*......
  • 【Azure Redis】Redis-CLI连接Redis 6380端口始终遇见 I/O Error
    问题描述使用Redis-cli连接Redis服务,因为工具无法直接支持TLS6380端口连接,所以需要使用stunnel配置TLS/SSL服务。根据文章(LinuxVM使用6380端口(SSL方式)连接AzureRedis(redis-cli&stunnel):https://www.cnblogs.com/lulight/p/14188279.html),配置stunnel后,始终无法连接成......
  • Redis 缓存击穿,缓存穿透,缓存雪崩原因+解决方案
    缓存击穿,缓存穿透,缓存雪崩的原因缓存击穿:key对应的数据存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。缓存穿透:key对应的数据在数据源并不存在,每次针对此key的请求从缓存......
  • redis连接失败
     本次连接redis失败记录,密码全为0,不加“”认证会失败springboot yml配置 密码为0时,要加“”很经典的错误,记录一下......
  • redis集群
    Redis集群本章是基于CentOS7下的Redis集群教程,包括:单机安装RedisRedis主从Redis分片集群1.单机安装Redis首先需要安装Redis所需要的依赖:yuminstall-ygcctcl然后将课前资料提供的Redis安装包上传到虚拟机的任意目录:例如,我放到了/tmp目录:解压缩:tar-xzfredis-6......
  • 分享一个 SpringBoot + Redis 实现「查找附近的人」的小技巧
    前言SpringDataRedis提供了十分简单的地理位置定位的功能,今天我就用一小段代码告诉大家如何实现。正文1、引入依赖<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>2、更......
  • redis-实战篇-商户查询缓存
    基本思路添加缓存的原则:动态数据不要加缓存缓存cache:数据交换的缓冲区。一般读写性能较高。比如浏览器缓存,浏览器会将一些经常使用的数据缓存到本机,这样在多次加载时就不需要访问服务器,而浏览器未命中的缓存则会去tomcat获取。缓存的作用:降低后端负载、提高读写效率、降低响应......