在springboot中两种方式使用缓存,一种是直接通过 RedisTemplate 来使用,另一种是使用 Spring Cache 集成 Redis(也就是注解的方式)。
RedisTemplate 方式不作说明,详细说明实现一下注解方式。
核心三个注解:
@Cachable
@CachePut
@CacheEvict
1.@Cachable
根据方法的请求参数对其结果进行缓存:
Key:缓存的 Key,可以为空,如果指定要按照 SPEL 表达式编写,如果不指定,则按照方法的所有参数进行组合。
Value:缓存的名称。
Condition:缓存的条件,可以为空,使用 SPEL 编写,返回 true 或者 false,只有为 true 才进行缓存。
写法:
@Cacheable(value = "user", key = "#id",condition="#id>1")
public User get(Integer id) {
针对这一句话进行一次比较:根据方法的请求参数对其结果进行缓存。
@Cacheable(value = "user", key = "#id",condition="#id>1")
@Override
public User get(Integer id) {
logger.info("进入get方法,当前获取对象:{}", userDao.selectById(id)==null?null:userDao.selectById(id).toString());
return userDao.selectById(id);
}
@Cacheable(value = "test", key = "#id",condition="#id>1")
@Override
public String getString(Integer id) {
logger.info("进入get方法,当前获取对象:{}", userDao.selectById(id)==null?null:userDao.selectById(id).toString());
return userDao.selectById(id).getUsername();
}
一个方法返回的是对象,一个方法返回的是字符串。
redis中存储结果:一个存的是字符串,一个存的是对象。(没有进行反序列化处理,大致能看出来不同就行了)
2.@CachePut
根据方法的请求参数对其结果进行缓存:
Key:缓存的 Key,可以为空,如果指定要按照 SPEL 表达式编写,如果不指定,则按照方法的所有参数进行组合。
Value:缓存的名称。
Condition:缓存的条件,可以为空,使用 SPEL 编写,返回 true 或者 false,只有为 true 才进行缓存。
和@Cachable不同的是,@CachePut这个注解可以确保方法被执行,同时方法的返回值也被记录到缓存中。
@Cacheable当重复使用相同参数调用方法的时候,方法本身不会被调用执行,即方法本身被略过了,取而代之的是方法的结果直接从缓存中找到并返回了。
3.@CacheEvict
根据条件对缓存进行清空:
Key:缓存的 Key,可以为空,如果指定要按照 SPEL 表达式编写,如果不指定,则按照方法的所有参数进行组合。
Value:缓存的名称。
Condition:缓存的条件,可以为空,使用 SPEL 编写,返回 true 或者 false,只有为 true 才进行缓存。
allEntries:是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存。
beforeInvocation:是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存。缺省情况下,如果方法执行抛出异常,则不会清空缓存。
理论知识结束,实践一下:
maven依赖:
org.springframework.boot
spring-boot-starter-data-redis
user实体类:这里必须要序列化,不然进行缓存时会出错。
public class User implements Serializable {
private int id;
private String username;
private String password;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
service和dao跳过,直接贴impl代码:注解使用都在这里面
@Service
public class RedisServiceImpl implements IRedisService {
public static Logger logger = LogManager.getLogger(RedisServiceImpl.class);
@Autowired
private UserDao userDao;
@CachePut(value ="user", key = "#user.id")
@Override
public User save(User user) {
userDao.insert(user);
logger.info("进入save方法,当前存储对象:{}", user.toString());
return user;
}
@CacheEvict(value="user", key = "#id")
@Override
public void delete(int id) {
userDao.deleteById(id);
logger.info("进入delete方法,删除成功");
}
@Cacheable(value = "user", key = "#id",condition="#id>1")
@Override
public User get(Integer id) {
logger.info("进入get方法,当前获取对象:{}", userDao.selectById(id)==null?null:userDao.selectById(id).toString());
return userDao.selectById(id);
}
@Cacheable(value = "test", key = "#id",condition="#id>1")
@Override
public String getString(Integer id) {
logger.info("进入get方法,当前获取对象:{}", userDao.selectById(id)==null?null:userDao.selectById(id).toString());
return userDao.selectById(id).getUsername();
}
}
最后是controller:使用的mp,不是重点,随便造点数据即可。
@RestController
@RequestMapping("redis")
public class RedisController {
public static Logger logger = LogManager.getLogger(RedisController.class);
@Autowired
private IRedisService redisService;
@GetMapping("/add")
public void add() {
User user = new User();
user.setId(3);
user.setUsername("abc");
user.setPassword("abc");
redisService.save(user);
logger.info("添加的用户信息:{}", user.toString());
}
@GetMapping("/delete")
public void delete() {
redisService.delete(3);
}
@GetMapping("/get/{id}")
public void get(@PathVariable("id") String idStr) throws Exception {
if (StringUtils.isBlank(idStr)) {
throw new Exception("id为空");
}
Integer id = Integer.parseInt(idStr);
User user = redisService.get(id);
logger.info("获取的用户信息:{}", user.toString());
}
@GetMapping("/getString/{id}")
public void getString(@PathVariable("id") String idStr) throws Exception {
if (StringUtils.isBlank(idStr)) {
throw new Exception("id为空");
}
Integer id = Integer.parseInt(idStr);
redisService.getString(id);
}
}
启动类上必须要开启注解:
@SpringBootApplication
@EnableCaching
public class ChuanApplication {
public static void main(String[] args) {
SpringApplication.run(ChuanApplication.class, args);
}
}
完成,进行接口测试。