redis缓存一致 做延时双删

发布时间 2023-11-17 14:35:46作者: wuyicode

提出现象

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


}