SpringBoot AOP + Redis delayed double deletion function in practice


<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

/**
 *Delayed double deletion
 **/
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target(ElementType.METHOD)
public @interface ClearAndReloadCache {<!-- -->
    String name() default "";
}

@Aspect
@Component
public class ClearAndReloadCacheAspect {<!-- -->

@Autowired
private StringRedisTemplate stringRedisTemplate;

/**
* entry point
*Entry point, entry point implemented based on annotations. Those with this annotation are all entry points for Aop aspects.
*
*/

@Pointcut("@annotation(com.pdh.cache.ClearAndReloadCache)")
public void pointCut(){<!-- -->

}
/**
* Surround notifications
* Surround notifications are very powerful and can determine whether and when the target method is executed, whether the method parameters need to be replaced during execution, and whether the return value needs to be replaced after execution.
* The first parameter of the surround notification must be of type org.aspectj.lang.ProceedingJoinPoint
* @param proceedingJoinPoint
*/
@Around("pointCut()")
public Object aroundAdvice(ProceedingJoinPoint proceedingJoinPoint){<!-- -->
    System.out.println("---------- Surround notification -----------");
    System.out.println("Target method name of surrounding notification: " + proceedingJoinPoint.getSignature().getName());

    Signature signature1 = proceedingJoinPoint.getSignature();
    MethodSignature methodSignature = (MethodSignature)signature1;
    Method targetMethod = methodSignature.getMethod();//Method object
    ClearAndReloadCache annotation = targetMethod.getAnnotation(ClearAndReloadCache.class);//Reflection to get the method object of the custom annotation

    String name = annotation.name();//Get the parameter of the method object of the custom annotation, which is name
    Set<String> keys = stringRedisTemplate.keys("*" + name + "*");//Fuzzy definition key
    stringRedisTemplate.delete(keys);//Fuzzy delete redis key value

    //Execute the business of modifying the database with double deletion annotations, that is, the method business in the controller
    Object proceed = null;
    try {<!-- -->
        proceed = proceedingJoinPoint.proceed();
    } catch (Throwable throwable) {<!-- -->
        throwable.printStackTrace();
    }

    //Open a thread and delay for 1 second (here is an example of 1 second, you can change it to your own business)
    // Delay deletion in the thread and return the result of the business code at the same time so that it does not affect the execution of the business code
    new Thread(() -> {<!-- -->
        try {<!-- -->
            Thread.sleep(1000);
            Set<String> keys1 = stringRedisTemplate.keys("*" + name + "*");//Fuzzy delete
            stringRedisTemplate.delete(keys1);
            System.out.println("----------After 1 second, the delayed deletion in the thread will be completed -----------");
        } catch (InterruptedException e) {<!-- -->
            e.printStackTrace();
        }
    }).start();

    return proceed;//Return the value of the business code
    }
}

server:
  port: 8082

spring:
  # redis setting
  redis:
    host: localhost
    port: 6379

  # cache setting
  cache:
    redis:
      time-to-live: 60000 # 60s

  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test
    username: root
    password: 1234


> Backend management system + user applet implemented based on Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element, supporting RBAC dynamic permissions, multi-tenancy, data permissions, workflow, three-party login, payment, SMS, mall, etc. Function
>
> * Project address: <https://github.com/YunaiV/yudao-cloud>
> * Video tutorial: <https://doc.iocoder.cn/video/>

# mp setting
mybatis-plus:
  mapper-locations: classpath*:com/pdh/mapper/*.xml
  global-config:
    db-config:
      table-prefix:
  configuration:
    # log of sql
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    #hump
    map-underscore-to-camel-case: true

DROP TABLE IF EXISTS `user_db`;
CREATE TABLE `user_db` (
  `id` int(4) NOT NULL AUTO_INCREMENT,
  `username` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

----------------------------
-- Records of user_db
----------------------------
INSERT INTO `user_db` VALUES (1, 'Zhang San');
INSERT INTO `user_db` VALUES (2, '李思');
INSERT INTO `user_db` VALUES (3, '王二');
INSERT INTO `user_db` VALUES (4, 'Mazi');
INSERT INTO `user_db` VALUES (5, '王三');
INSERT INTO `user_db` VALUES (6, '李三');

/**
 * User control layer
 */
@RequestMapping("/user")
@RestController
public class UserController {<!-- -->
    @Autowired
    private UserService userService;

    @GetMapping("/get/{id}")
    @Cache(name = "get method")
    //@Cacheable(cacheNames = {"get"})
    public Result get(@PathVariable("id") Integer id){<!-- -->
        return userService.get(id);
    }

    @PostMapping("/updateData")
    @ClearAndReloadCache(name = "get method")
    public Result updateData(@RequestBody User user){<!-- -->
        return userService.update(user);
    }

    @PostMapping("/insert")
    public Result insert(@RequestBody User user){<!-- -->
        return userService.insert(user);
    }

    @DeleteMapping("/delete/{id}")
    public Result delete(@PathVariable("id") Integer id){<!-- -->
        return userService.delete(id);
    }
}

/**
 * service layer
 */
@Service
public class UserService {<!-- -->

    @Resource
    private UserMapper userMapper;

    public Result get(Integer id){<!-- -->
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getId,id);
        User user = userMapper.selectOne(wrapper);
        return Result.success(user);
    }

    public Result insert(User user){<!-- -->
        int line = userMapper.insert(user);
        if(line > 0)
            return Result.success(line);
        return Result.fail(888,"Failed to operate database");
    }

    public Result delete(Integer id) {<!-- -->
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getId, id);
        int line = userMapper.delete(wrapper);
        if (line > 0)
            return Result.success(line);
        return Result.fail(888, "Failed to operate the database");
    }

    public Result update(User user){<!-- -->
        int i = userMapper.updateById(user);
        if(i > 0)
            return Result.success(i);
        return Result.fail(888,"Failed to operate database");
    }
}







https://gitee.com/jike11231/redisDemo.git

Reprint: https://mp.weixin.qq.com/s/VBr3E086U58PyQkNdFfNzg