首页 > 数据库 >redis缓存一致 做延时双删

redis缓存一致 做延时双删

时间:2023-11-17 14:48:23浏览次数:34  
标签:缓存 双删 keys redis org employee import annotation

提出现象

  1. 做数据库更新A 
  2. redis缓存刷新A
  3. 做据库更新B
  4. redis缓存更新B

如果正常执行1,2,3,4步骤,一切正常。但是在高并发的情况下, 执行步骤是 1,3,4,2,导致数据库和缓存不一致。

提出解决方法,做延时双删。

   // 操作数据库的方法 
  @PostMapping("/employee/update") @ClearAndReloadCache(name = "employee") public void update(){ Employee employee = new Employee(); employee.setEmployeeId(BigInteger.valueOf(100)); employee.setHireDate(new Date()); employeeService.update(employee); }
// 注解类
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface ClearAndReloadCache { String name() default ""; }
import javafx.concurrent.Task;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

@Component
@Aspect
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
public class ClearAndReloadCacheAop {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    private ExecutorService executorService;

    {
        executorService = Executors.newCachedThreadPool();
    }

    @Pointcut("@annotation(com.jin.redis.ClearAndReloadCache)")
    public void pointCut1() {
    }


    @Around(value = "pointCut1()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) {
        Object proceed = null;

        MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
        System.out.println(methodSignature.getName());

        ClearAndReloadCache annotation = methodSignature.getMethod().getAnnotation(ClearAndReloadCache.class);
        if (annotation == null) {
            try {
                proceed = proceedingJoinPoint.proceed();
            } catch (Throwable e) {
                throw new RuntimeException(e);
            }
        } else {
            String keyName = annotation.name();
            //模糊定义key
            Set<String> keys = stringRedisTemplate.keys("*" + keyName + "*");
            assert keys != null;
            // 第一次删除
            stringRedisTemplate.delete(keys);

            // 执行数据库的操作
            try {
                proceed = proceedingJoinPoint.proceed();
            } catch (Throwable e) {
                throw new RuntimeException(e);
            }

            Task<Void> task = new Task<Void>() {
                @Override
                protected Void call() throws Exception {
                    // 休眠 1s 是为了让数据库操作完成
                    TimeUnit.SECONDS.sleep(1);
                    // 第二次删除
                    Set<String> keys = stringRedisTemplate.keys("*" + keyName + "*");
                    assert keys != null;
                    stringRedisTemplate.delete(keys);
                    return null;
                }
            };
            executorService.submit(task);

        }
        return proceed;
    }


}

 

标签:缓存,双删,keys,redis,org,employee,import,annotation
From: https://www.cnblogs.com/wuyicode/p/17838688.html

相关文章

  • 为什么要用Redis做缓存?为什么用Redis而不用map和Guava?
    从请求数据的性能和并发角度来回答这两个问题,假如用户是第一次访问数据库中的某些数据,第一次访问当然会比较慢,因为是直接从硬盘上读取的,数据通过磁盘IO从磁盘上来到内存中,然后通过网络通信传输给用户,假如我们在第一次读取数据时,将数据存储到内存中,然后第二次以后都从内存中直接读......
  • 数据和缓存如何保持一致
    目前业界里有哪些方案,让数据库和缓存的数据保持一致了?大概有以下四种大厂模式(监听binlog+mq)大厂模式主要是通过监听数据库的binlog(比如mysqlbinlog);通过binlog把数据库数据的更新操作日志(比如insert,update,delete),采集到后,通过MQ的方式,把数据同步给下游对应的消费者;下游消费者拿......
  • 【docker】docker中装Redis集群
    一、搭建步骤1、启动容器#关闭防火墙systemctlstartdocker2、新建6个docker容器redis实例dockerrun-d--nameredis-node-1--nethost--privileged=true-v/data/redis/share/redis-node-1:/dataredis--cluster-enabledyes--appendonlyyes--port6381do......
  • linux系统部署redis单点服务
    1、下载rediswgethttps://download.redis.io/releases/redis-5.0.9.tar.gz2、解压tarzxfredis-5.0.9.tar.gz3、移动redis解压目录mvredis-5.0.9/usr/local/redis4、编译cd/usr//local/redismake5、安装makeprefix=/usr/local/redisinstall6、配置配......
  • 记一个RedisConfig坑
    记一个RedisConfig坑springboot整合redis,RedisConfig配置lettuceConnectionFactory时遇到的一个坑。配置文件:spring:redis:host:127.0.0.1port:6379password:123456RedisConfig:@ConfigurationpublicclassRedisConfig{@BeanpublicLett......
  • Linux环境配置redis集群启动、停止脚本
    1、创建redisc脚本vim/etc/init.d/redisc2、编辑脚本内容#!/bin/sh#chkconfig:23458090#SimpleRedisinit.dscriptconceivedtoworkonLinuxsystems#asitdoesuseofthe/procfilesystem.REDISNODE1=7001REDISNODE2=7002REDISNODE3=7003REDISNODE4=70......
  • Redis缓存淘汰策略
    八个淘汰策略volatile-randomvolatile-lruvolatile-lfuvolatile-ttlnoevictionallkeys-lruallkeys-randomallkeys-lfulru标准LRU算法是由双向链表及Hash表实现,具体代码实现可以参考LRU算法Redis中的LRU算法实现有所变化:Reids没有使用双向链表维护数据页的访问顺序......
  • redis官方集群搭建
    1.下载releases7.2.0(最好下载源码在服务器编译):https://packages.redis.io/redis-stack/redis-stack-server-7.2.0-v6.rhel7.x86_64.tar.gz?_gl=1*jh1xlt*_ga*MTA3MjY3MzAyMi4xNjgwNzQ0NTE2*_ga_8BKGRQKRPV*MTcwMDEzNzc3NS41LjEuMTcwMDEzNzgwNi4yOS4wLjA.*_gcl_au*MTI3NTM4NTEwNi4xN......
  • Redis 缓存系统常见问题及解决方案(缓存击穿,缓存穿透,缓存雪崩)
    1、缓存穿透缓存穿透指当用户在Redis缓存系统执行一条无效查询时,这条无效查询将穿透Redis缓存系统并向MySQL数据库请求数据,而MySQL数据库也获取不到数据。黑客可以利用缓存穿透原理,恶意执行大量无效查询,这将会对MySQL数据库的访问造成很大的压力解决方法:1、缓存......
  • Redis7 数据持久化AOF
    1、官网介绍2、是什么以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录)只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作默认情况下,redis......