随笔 - 43  文章 - 0  评论 - 1  阅读 - 80506

redis缓存一致 做延时双删

提出现象

  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;
    }


}
复制代码

 

posted on   wuyicode  阅读(120)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· DeepSeek在M芯片Mac上本地化部署
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示