# springboot-redis延时双删
**Repository Path**: jike11231/redisDemo
## Basic Information
- **Project Name**: springboot-redis延时双删
- **Description**: springboot-redis延时双删
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 26
- **Forks**: 35
- **Created**: 2022-08-09
- **Last Updated**: 2025-02-16
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
**demo地址:[https://gitee.com/pdh_gitee/redis-cache-demo.git](https://gitee.com/pdh_gitee/redis-cache-demo.git)**。
本地必须有Redis,这是前提,本次所有demo均是在windows上测试。在spring boot项目中,通常采用使用自动缓存策略即可,也可以使用RedisTemplate类操作redis,可配置redis(当然,这样很麻烦,除非有特别的业务需求)。
使用redis缓存的时候:**使用@Cacheable自动缓存,就需要关闭RedisTemplate手动缓存的配置信息(包括缓存方法上的注解,配置类上的@Configuration注解等),反之亦然。**
# 一、新建SpringBoot项目
新建SpringBoot项目,【[点击我查看如何快速搭建SpringBoot项目](https://blog.csdn.net/yeahPeng11/article/details/120033200)】。
## 1.依赖
导入redis、swagger3、lombok、mp、web等依赖。
```xml
org.springframework.boot
spring-boot-starter-data-redis
io.springfox
springfox-boot-starter
3.0.0
com.baomidou
mybatis-plus-boot-starter
3.4.3
org.springframework.boot
spring-boot-starter-web
mysql
mysql-connector-java
runtime
org.projectlombok
lombok
true
```
## 2.配置文件
application.yml
```yml
debug: true # Viewing Automatic Configuration
server:
port: 8082
spring:
redis:
host: localhost
port: 6379
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/test
username: root
password: # you root password
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
```
## 3.sql和实体类
执行sql脚本即可(存放在demo的sql包下)
```sql
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;
INSERT INTO `user_db` VALUES (1, '张三');
INSERT INTO `user_db` VALUES (2, '李四');
INSERT INTO `user_db` VALUES (3, '王二');
INSERT INTO `user_db` VALUES (4, '麻子');
INSERT INTO `user_db` VALUES (5, '王三');
INSERT INTO `user_db` VALUES (6, '李三');
INSERT INTO `user_db` VALUES (7, 'hh');
```
User
```java
package com.pdh.entity;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import nonapi.io.github.classgraph.json.Id;
import org.apache.commons.lang3.StringUtils;
import java.io.Serializable;
/**
*@Author: 彭_德华
*@Date: 2021-10-26 11:24
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("user_db")
public class User implements Serializable {
@Id
private Integer id;
private String username;
}
```
## 4.统一返回Result
所有请求统一返回结果
```java
package com.pdh.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.io.Serializable;
/**
* @Author: 彭_德华
* @Date: 2021-10-26 15:27
* 结果统一封装
*/
@Data
@AllArgsConstructor
public class Result implements Serializable {
private boolean success;
private int code;
private String msg;
private Object data;
/**
* success方法,标识成功
* @param data
* @return
*/
public static Result success(Object data){
return new Result(true,200,"success",data);
}
/**
* fail方法,标识失败
* @param code
* @param msg
* @return
*/
public static Result fail(int code, String msg){
return new Result(false,code,msg,null);
}
}
```
# 二、连接测试
通过swagger3测试接口,接口收到请求后访问持久层获取到mysql中的数据。访问步骤:浏览器-》controller接口-》service-》mapper-》mysql,访问到数据后在逐一返回。
## 1.controller
UserController
```java
@RequestMapping("/user")
@RestController
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/get/{id}")
public User get(@PathVariable("id") Integer id){
return userService.get(id);
}
@PostMapping("/insert")
public boolean insert(@RequestBody User user){
return userService.insert(user);
}
@DeleteMapping("/delete/{id}")
public boolean delete(@PathVariable("id") Integer id){
return userService.delete(id);
}
}
```
## 2.service
UserService
```java
@Service
public class UserService {
@Resource
private UserMapper userMapper;
public User get(Integer id){
LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getId,id);
User user = userMapper.selectOne(wrapper);
return user;
}
public boolean insert(User user){
int line = userMapper.insert(user);
if(line > 0)
return true;
return false;
}
public boolean delete(Integer id){
LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getId,id);
int line = userMapper.delete(wrapper);
if(line > 0)
return true;
return false;
}
}
```
## 3.mapper
UserMapper
```java
package com.pdh.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.pdh.entity.User;
/**
* @Author: 彭_德华
* @Date: 2021-10-26 13:17
*/
public interface UserMapper extends BaseMapper {
}
```
## 4.swagger3启动测试
数据库连接正确,启动项目。
访问:`http://localhost:8082/swagger-ui/index.html`(端口application自定)。
进入测试页面,测试get接口,得到如下响应(与数据表数据对应,操作成功)。

# 三、Redis缓存(*)
使用Redis缓存的最大好处无非就两点:**提升系统响应速度 和 降低数据库交互压力**。redis的数据缓存到内存中,访问速度特别快。看一下使用redis缓存和不使用redis缓存(以下分析只考虑数据缓存到redis和数据库中):

**有redis做缓存**
第一次访问某一数据的时候(每一次访问都会查询redis),redis里面没有指定数据,就会访问数据库获取到数据,返回后把第一次获取到的数据回填到redis中,在过期时间内再次访问该数据的时候,就直接返回,不会再访问数据库。在对数据请求非常多的时候,采用这种策略是必须的。
**直接与数据库交互**
每一次访问都是直接请求数据库,当请求量很大的时候,数据库的压力就非常大,直接导致系统响应变慢。
## 1.redis缓存策略
缓存策略选择很多,我使用过的有两种:
**(1)使用@EnableCaching+@Cacheable实现自动缓存,(2)使用RedisTemplate手动缓存(注解+aop)**。
在刚开始接触缓存的时候,第一种@EnableCaching+@Cacheable实现自动缓存肯定简单很多,但是,对程序开发有一定接触的帅b都知道,自动配置的redis缓存灵活些不高,无法定制自己的redis缓存需求。
而对于 **使用RedisTemplate手动缓存(注解+aop)** 来说,我们就获得了redis缓存的绝对控制权,缓存的逻辑由我们自己实现。这使得我们在实际开发过程中,就灵活许多,可以配置很多信息,比如log输出、缓存时间更新、为不同方法设置不同的缓存过期时间、自定义key格式、... ... 等等。
下面写出两种方式的使用示例(后在分析一下源码)。
## 2.@Cacheable自动缓存
@Cacheable标注在需要缓存的 **方法或类** 上,@EnableCaching表示开启自动缓存(可以放在启动类、配置类上)。
编写配置类RedisConfig1,自动生成的key的形式是: `cacheNames::params`。但是为了很清晰的看出缓存的key是那个方法、什么参数的值,那就需要自定义key的生成形式,即重写CachingConfigurerSupport类的keyGenerator()方法:
> - CachingConfigurerSupport 类提高了很多定制redis缓存配置的功能,具体怎么实现,这个还得继续查看官方手册~ 【[点击我跳转到springboot集成redis的细节](http://felord.cn/_doc/_springboot/2.1.5.RELEASE/_book/pages/spring-boot-features.html#boot-features-caching-provider-redis)】里面提到设置过期时间这个问题,好像只能是使用RedisTemplate才能实现。
> - RedisConfig的更多设置,参考【[https://blog.csdn.net/weixin_40623736/article/details/98097708](https://blog.csdn.net/weixin_40623736/article/details/98097708)】
```java
package com.pdh.config;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* @Author: 彭_德华
* @Date: 2021-10-27 16:32
*/
@EnableCaching
@Configuration
public class RedisConfig1 extends CachingConfigurerSupport {
@Bean
public RedisTemplate