缓存中间件Redis - 基于SpringBoot
步骤五、在相应的方法上加上缓存注解@Cacheable、@CachePut、@CacheEvict
步骤一、加入Redis相关依赖
该项目使用springboot 2.4.0版本
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!--Redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
引入redis相关的依赖以启用Redis作为项目的缓存,否则Springboot默认使用SimpleCacheConfiguration配置类,启用Springboot内部默认的缓存,该默认缓存使用ConcurrentHashMap缓存数据,而不会使用RedisCacheConfiguration配置类。
注意:
在Springboot1.5.22版本之后,如果要使用RedisTemplate直接对Redis进行操作,需要手动引入jedis。本文使用的demo项目没有使用RedisTemplate对Redis进行操作,所以未引入jedis。
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
PS:spring-boot-starter-data-redis 1.5.22之前的版本中直接引入的jedis,spring-boot-starter-data-redis 1.5.22之后的版本中不再直接引入jedis,而是引入的spring-data-redis。在spring-data-redis中引入了jedis,但是引入的jedis是可选的(optional=true), optional=true的依赖不会在模块之间进行传递。也就是说,如果你的项目使用的是Spring-boot-starter-data-redis1.5.22之后的版本,那么jedis不会出现在项目依赖中。如果需要使用jedis,需要手动引入jedis对应版本的依赖,否则不能通过注入RedisTemplate来操作Redis。
步骤二、配置Redis服务器的相关属性
spring:
redis:
host: localhost
port: 6379
password: password1
如果Redis服务器在本地,并且端口是6379,那么host和port不用配置,因为默认的spring.redis.host=localhost,spring.redis.port=6379
步骤三、开启基于注解的缓存
在SpringBoot项目的启动类上加上@EnableCaching注解
步骤四、数据对象必须可序列化
简单的数据对象实现Serializable接口,如下
package com.example.demo.entity;
import java.io.Serializable;
import lombok.Data;
@Data
public class User implements Serializable{
private Long id;
private String name;
private String address;
}
复杂的数据对象(如多层调用)需要重写readObject() writeObject()方法
步骤五、在相应的方法上加上缓存注解@Cacheable、@CachePut、@CacheEvict
package com.example.demo.service.impl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import com.example.demo.service.UserService;
@Service
public class UserServiceImpl implements UserService{
private static final String CACHE_USER = "USER";
final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);
@Autowired
UserMapper userMapper;
@Override
@Transactional
@CachePut(cacheNames = CACHE_USER, key = "#user.id", condition = "#result != null") // @CachePut 调用方法并且更新缓存
public User insert(User user) {
userMapper.insert(user);
return user;
}
@Override
@Cacheable(cacheNames = CACHE_USER, key = "#id") // @Cacheable 缓存命中则不调用方法,否则调用方法并且更新缓存
public User getUserById(Long id) {
logger.info("UserService - getUserById(id = " + id+")");
return userMapper.getUserById(id);
}
@Override
@Transactional
@CacheEvict(cacheNames = CACHE_USER, key = "#user.id", condition = "#result != null")
public User updateUser(User user) {
logger.info("UserService - updateUser(" + user+")");
userMapper.updateUser(user);
return user;
}
@Override
@Transactional
@CacheEvict(cacheNames = CACHE_USER, key = "#id", condition = "#result > 0")
public int deleteUserById(Long id) {
logger.info("UserService - deleteUserById(id = " + id+")");
return userMapper.deleteUserById(id);
}
}
在方法上加上注解后,并且配置相关注解的属性。如:cacheNames、key、keyGenerator、condition、unless。
cacheNames:缓存的名字。如上述代码中,将所有关于User的数据缓存到"User"下,也可以理解为:根据不同的数据,将其分组。User相关的数据就缓存到"User"下,Item相关的数据缓存到"Item"下。
key: 键值对中的key。因为数据在Redis中是以key/value的形式存储的,因此需要设置数据缓存键值对中的key。上述代码简单地将user数据对象的id作为key,所以id为1的user在缓存中的key是User::1
keyGenerator:key的生成器,用于自定义key的生成方式。key和keyGenerator指定一个即可。
condition:condition指定一个SpEL表达式,表示是否将方法返回值进行缓存,true则缓存,否则不缓存。
unless:与condition类似,只是表达的意思恰好相反。unless指定一个SpEL表达式,表示是否将方法返回值进行缓存,true则不缓存,否则缓存。
SpEL表达式
名字 | 位置 | 描述 | 示例 |
---|---|---|---|
methodName | root object | 当前被调用的方法名 | #root.methodName |
method | root object | 当前被调用的方法 | #root.method.name |
target | root object | 当前被调用的目标对象 | #root.target |
targetClass | root object | 当前被调用的目标对象类 | #root.targetClass |
args | root object | 当前被调用的方法的参数列表 | #root.args[0] |
caches | root object | 当前方法调用使用的缓存列表(如@Cacheable(value={“cache1”, “cache2”})),则有两个cache | #root.caches[0].name |
argument name | evaluation context | 方法参数的名字. 可以直接 #参数名 ,也可以使用 #p0或#a0 的形式,0代表参数的索引; | #iban 、 #a0 、 #p0 |
result | evaluation context | 方法执行后的返回值(仅当方法执行之后的判断有效,如‘unless’,’cache put’的表达式 ’cache evict’的表达式beforeInvocation=false) | #result |
记录学习Redis,仅供参考,不当之处欢迎指出。