前言
Spring Boot 集成 Redis 实现数据缓存,只需要添加一些注解,就无侵入地使用缓存了,无需额外的代码。
步骤
Spring Boot 集成 Redis 实现缓存主要分为以下三步:
1)加入 Redis 依赖;
2)加入 Redis 配置;
3)添加 Redis 缓存相关注解。
一、加入依赖
首先我们创建一个项目,并在项目中加入 Redis 依赖,项目依赖如下所示(由于使用 Redis 连接池,需额外引入 commons-pool2):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
在 spring-boot-starter-data-redis 1.X 版本中默认使用 Jedis 客户端,而在 2.X 版本默认使用 Lettuce 客户端。如果更习惯使用 Jedis,可从 spring-boot-starter-data-redis 中排除 Lettuce 并引入 Jedis 依赖。
二、加入配置
①在配置文件 application.properties 中配置 Redis 的相关参数,具体内容如下:
#Redis 数据库索引(0~15,默认为 0)
spring.redis.database=0
#修改为自己的redis实例所在的ip地址
spring.redis.host=127.0.0.1
#Redis 密码,如果没有就默认不配置此参数
spring.redis.password= spring.redis.port=6379
#Redis 连接的超时时间 https://blog.csdn.net/haveqing/article/details/86524450 spring.redis.timeout=1000ms #连接池最大连接数(使用负值表示没有限制) spring.redis.lettuce.pool.max-active=20 #连接池最大阻塞等待时间(使用负值表示没有限制) spring.redis.lettuce.pool.max-wait=-1ms #连接池中的最大空闲连接 spring.redis.lettuce.pool.max-idle=10 #连接池中的最小空闲连接
spring.redis.lettuce.pool.min-idle=0
②接下来在 config 包下创建一个 Redis 配置类 RedisConfig,在配置类上加入注解 @Configuration,注入一个 CacheManager 来配置一些相关信息,代码如下:
@Configuration
public class RedisConfig {
/**
* 首先通过 RedisCacheConfiguration 生成默认配置,然后对缓存进行自定义化配置,比如过期时间、缓存前缀、key/value 序列化方法等,然后构建出一个 RedisCacheManager
* @param factory
* @return
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(30))
//测试了一下,如果此处配置了key的前缀,则@CacheConfig(cacheNames = "user")无效,redis中的key前缀为cache:user: 可参见 https://blog.csdn.net/star_apple/article/details/105025008
.prefixKeysWith("cache:user:")
.disableCachingNullValues()
.serializeKeysWith(keySerializationPair())
.serializeValuesWith(valueSerializationPair());
Map<String, RedisCacheConfiguration> cacheConfig = new HashMap<>();
return RedisCacheManager.builder(factory) .withInitialCacheConfigurations(cacheConfig) .cacheDefaults(redisCacheConfiguration) .build();
}
//为 key 配置序列化
private RedisSerializationContext.SerializationPair<String> keySerializationPair() {
return RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer());
}
//为 value 配置序列化
private RedisSerializationContext.SerializationPair<Object> valueSerializationPair() {
return RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer());
}
}
首先通过 RedisCacheConfiguration 生成默认配置,然后对缓存进行自定义化配置,比如过期时间、缓存前缀、key/value 序列化方法等,然后构建出一个 RedisCacheManager,其中通过 keySerializationPair 方法为 key 配置序列化,valueSerializationPair 为 value 配置序列化。
③启动类添加开启缓存注解
@SpringBootApplication
@EnableCaching
public class RedisCacheApplication{
private static final Logger logger = LoggerFactory.getLogger(RedisCacheApplication.class);
public static void main(String[] args) {
SpringApplication.run(RedisCacheApplication.class, args);
logger.info("项目运行");
}
}
@EnableCaching 表明开启缓存,Spring Boot 会自动配置 Redis 缓存的 CacheManager。
三、添加 Redis 缓存相关注解
①定义用户实体类
在 entity 包下创建一个用户实体类:
public class User {
private Long id;
private String name;
private String password;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
②在服务中使用 SpringCache 注解
在 service 包下定义用户接口,分别包含添加用户、查询用户、更新用户以及删除用户四个接口,具体代码如下:
public interface UserService {
void addUser(User user);
User getUserById(Long id);
User updateUser(User user);
void deleteById(Long id);
}
然后编写实现类,为了方便演示,在这里使用 Map<Long, User> userMap,没有真正连接数据库,下面使用到的注解有 @CacheConfig、@Cacheable、@CachePut 以及 @CacheEvict,具体代码如下:
@Service
@CacheConfig(cacheNames = "user")
public class UserServiceImpl implements UserService {
//此处使用HashMap来存储数据,表示数据库交互操作
Map<Long, User> userMap = Collections.synchronizedMap(new HashMap<>());
@Override
public void addUser(User user) {
userMap.put(user.getId(), user);
}
@Override
@Cacheable(key = "#id")
public User getUserById(Long id) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (!userMap.containsKey(id)) {
return null;
}
return userMap.get(id);
}
@Override
@CachePut(key = "#user.id")
public User updateUser(User user) {
if (!userMap.containsKey(user.getId())) {
throw new RuntimeException("不存在该用户");
}
User newUser = userMap.get(user.getId());
newUser.setPassword(user.getPassword());
userMap.put(newUser.getId(), newUser);
return newUser;
}
@Override
@CacheEvict(key = "#id")
public void deleteById(Long id) {
userMap.remove(id);
}
}
简单说明一下这几个注解:
@CacheConfig 类级别的缓存注解,允许共享缓存名称。
@Cacheable 触发缓存的入口。 一般用于查询操作,根据 key 查询缓存。如果 key 不存在,就去查询数据库,并把查询结果更新到缓存中。如果 key 存在,直接查询缓存中的数据。
@CacheEvict 触发移除缓存。根据 key 删除缓存中的数据。
@CacahePut 触发更新缓存。一般用于更新和插入操作,每次都会请求 db,通过 key 去 Redis 中进行操作。如果 key 存在,更新内容。如果 key 不存在,插入内容。
③最后,在 controller 包下创建一个 UserController 类,提供用户 API 接口(未使用数据库),代码如下:
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id) {
return ResponseEntity.status(HttpStatus.CREATED).body(userService.getUserById(id));
}
@PostMapping
public ResponseEntity<String> createUser(@RequestBody User user) {
userService.addUser(user);
return ResponseEntity.status(HttpStatus.CREATED).body("SUCCESS");
}
@PutMapping
public ResponseEntity<User> updateUser(@RequestBody User user) {
return ResponseEntity.status(HttpStatus.CREATED).body(userService.updateUser(user));
}
@DeleteMapping("/{id}")
public ResponseEntity<String> deleteUser(@PathVariable Long id) {
userService.deleteById(id);
return ResponseEntity.status(HttpStatus.CREATED).body("SUCCESS");
}
}
测试
①启动项目,先调用添加用户接口,http://localhost:8080/user 来添加以下数据:
{
"id": 1,
"name": "pino",
"password": "1234"
}
②调用查询数据接口:http://localhost:8080/user/1 ,可以看到第一次调用时,耗时超过3s。
接着我们进行第二次调用,接口很快返回,说明缓存生效了。
③调用更新接口, http://localhost:8080/user
再次调用查询接口,返回最新数据,返回也很快。
总结
在Spring Boot框架中集成 Redis 实现数据缓存并不复杂,Spring 提供了缓存注解,使用这些注解可以有效简化编程过程。
遇到的问题:
springboot2 配置redis报错 redis timeout Value '1000' is not a valid duration解决办法:
解决方法:https://blog.csdn.net/haveqing/article/details/86524450
@CacheConfig(cacheNames = "user") 不生效
原因:https://blog.csdn.net/star_apple/article/details/105025008
参考链接:https://www.jianshu.com/p/e2d9cd3a5a8e
https://www.tianheyu.top/archives/springboot-redis-cache