在上一篇文章(《SpringBoot(二十四)整合Redis》)中,已经实现了Spring Boot对Redis的整合,既然已经讲到Cache了,今天就介绍介绍缓存注解。各家互联网产品现在数据量越来越大,其快速增长造成网络拥塞和服务器超载,导致客户访问延迟增大,服务质量日益显现出来。缓存技术被认为是减轻服务器负载、降低网络拥塞、增强可扩展性的有效途径之一。

v概念介绍

Spring为我们提供了几个注解来支持Spring Cache。其核心主要是@Cacheable和@CacheEvict。使用@Cacheable标记的方法在执行后Spring Cache将缓存其返回结果,而使用@CacheEvict标记的方法会在方法执行前或者执行后移除Spring Cache中的某些元素。下面我们将来详细介绍一下Spring基于注解对Cache的支持所提供的几个注解。

Spring Cache常见概念介绍

名称 解释
Cache 缓存接口,定义缓存操作。实现有:RedisCache、EhCacheCache、ConcurrentMapCache等
CacheManager 缓存管理器,管理各种缓存(cache)组件
@Cacheable 主要针对方法配置,能够根据方法的请求参数对其进行缓存
@CacheEvict 清空缓存
@CachePut 保证方法被调用,又希望结果被缓存。
与@Cacheable区别在于是否每次都调用方法,常用于更新
@EnableCaching 开启基于注解的缓存
keyGenerator 缓存数据时key生成策略
serialize 缓存数据时value序列化策略
@CacheConfig 统一配置本类的缓存注解的属性

注解(@Cacheable/@CachePut/@CacheEvict)的主要参数

名称 解释 example
value 缓存的名称,在 spring 配置文件中定义,必须指定至少一个 e.g.
@Cacheable(value=”mycache”) 或者
@Cacheable(value={”cache1”,”cache2”}
key 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,
如果不指定,则缺省按照方法的所有参数进行组合
e.g.
@Cacheable(value=”testcache”,key=”#id”)
condition 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,
只有为 true 才进行缓存/清除缓存
e.g.@Cacheable(value=”testcache”,condition=”#userName.length()>2”)
unless 否定缓存。当条件结果为TRUE时,就不会缓存。 e.g.@Cacheable(value=”testcache”,unless=”#userName.length()>2”)
allEntries
(@CacheEvict )
是否清空所有缓存内容,缺省为 false,如果指定为 true,
则方法调用后将立即清空所有缓存
e.g.
@CachEvict(value=”testcache”,allEntries=true)
beforeInvocation
(@CacheEvict)
是否在方法执行前就清空,缺省为 false,如果指定为 true,
则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法
执行抛出异常,则不会清空缓存
e.g.
@CachEvict(value=”testcache”,beforeInvocation=true)

v准备工作

1.1 引入依赖pom.xml

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

激活启动类注解@EnableCaching

v实战演练

2.1 添加service层

package com.demo.service;

import com.demo.pojo.UserDetails;

/**
* Created by toutou on 2019/1/20.
*/
public interface CacheService {
UserDetails getUserDetailsByUid(int uid); UserDetails updateUserInfo(UserDetails userDetails); int delUserInfoById(int uid);
}
package com.demo.service;

import com.demo.dao.UserDetailsMapper;
import com.demo.pojo.UserDetails;
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; /**
* Created by toutou on 2019/1/20.
*/
@Service
public class CacheServiceImpl implements CacheService{ @Autowired
UserDetailsMapper userDetailsMapper; @Override
@Cacheable(value = "user_details", key = "#uid", unless="#result == null")
public UserDetails getUserDetailsByUid(int uid){
System.out.println(" Cacheable 有请求过来了");
UserDetails userDetails = userDetailsMapper.getUserDetailsByUid(uid);
return userDetails;
} @Override
@CachePut(value = "user_details", key = "#user.id")
public UserDetails updateUserInfo(UserDetails user){
System.out.println(" CachePut 有请求过来了");
if(userDetailsMapper.updateByPrimaryKeySelective(user) > 0) {
// 这里也可以直接在updateByPrimaryKeySelective的方法里,修改后直接查询出该记录返回UserDetails实例,看需求。
user = userDetailsMapper.getUserDetailsByUid(user.getId());
return user;
}else{
return null;
}
} @Override
@CacheEvict(value = "user_details", key = "#uid")
public int delUserInfoById(int uid){
System.out.println(" CacheEvict 有请求过来了");
return userDetailsMapper.deleteByPrimaryKey(uid);
}
}

unless="#result == null"是指当查询为空时,不缓存,默认是空也会缓存。

2.2 添加CacheController

package com.demo.controller;

import com.demo.pojo.UserDetails;
import com.demo.service.CacheService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; /**
* Created by toutou on 2019/1/20.
*/
@RestController
@Slf4j
public class CacheController { @Autowired
CacheService cacheService; @RequestMapping(value = "/cache/getuserbyid")
public UserDetails getUserDetailsByUid(int uid){
try {
return cacheService.getUserDetailsByUid(uid);
}catch (Exception e){
System.out.println(e.toString());
return null;
}
} @RequestMapping(value = "/cache/updateuserinfo")
public int updateUserInfo(int uid, String city){
UserDetails userDetails = new UserDetails();
userDetails.setId(uid);
userDetails.setCity(city);
userDetails = cacheService.updateUserInfo(userDetails);
return userDetails == null ? 0 : userDetails.getUid();
} @RequestMapping(value = "/cache/deluserinfobyid")
public int delUserInfoById(int uid){
return cacheService.delUserInfoById(uid);
}
}

2.3 实现Serializable接口

v效果展示

3.1 Cacheable效果

当我们本地请求http://localhost:8081/cache/getuserbyid?uid=5接口时,可以看到控制台输出Cacheable 有请求过来了,而后续再次请求该接口时,不会再输出Cacheable 有请求过来了,这是因为直接走了缓存机制了,CacheServiceImpl的方法不再被调用。

通过Redis可以看到,user_details::5的记录已被创建。

3.2 CachePut效果

当我们本地请求http://localhost:8081/cache/updateuserinfo?uid=5&city=首都 接口时,将更新数据库和Redis中对应的字段值。

查询接口,更新成功。控制台再次输出Cacheable 有请求过来了

3.3 CacheEvict效果

当我们本地请求http://localhost:8081/cache/deluserinfobyid?uid=5 接口时,将删除数据中和Redis中的数据。

v博客总结

Redis和@Cacheable、@CachePut、@CacheEvict结合使用,效果挺好,结合这篇和上篇文章(《SpringBoot(二十四)整合Redis》),可以尝试着结合使用试试。

v源码地址

https://github.com/toutouge/javademosecond/tree/master/hellospringboot

作  者:请叫我头头哥

出  处:http://www.cnblogs.com/toutou/

关于作者:专注于基础平台的项目开发。如有问题或建议,请多多赐教!

版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信

声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是作者坚持原创和持续写作的最大动力!

SpringBoot进阶教程(二十五)整合Redis之@Cacheable、@CachePut、@CacheEvict的应用的更多相关文章

  1. SpringBoot进阶教程(二十九)整合Redis 发布订阅

    SUBSCRIBE, UNSUBSCRIBE 和 PUBLISH 实现了 发布/订阅消息范例,发送者 (publishers) 不用编程就可以向特定的接受者发送消息 (subscribers). Ra ...

  2. SpringBoot进阶教程(二十八)整合Redis事物

    Redis默认情况下,事务支持被禁用,必须通过设置setEnableTransactionSupport(true)为使用中的每个redistplate显式启用.这样做会强制将当前重新连接绑定到触发m ...

  3. SpringBoot进阶教程(二十六)整合Redis之共享Session

    集群现在越来越常见,当我们项目搭建了集群,就会产生session共享问题.因为session是保存在服务器上面的.那么解决这一问题,大致有三个方案,1.通过nginx的负载均衡其中一种ip绑定来实现( ...

  4. SpringBoot进阶教程(二十四)整合Redis

    缓存现在几乎是所有中大型网站都在用的必杀技,合理的利用缓存不仅能够提升网站访问速度,还能大大降低数据库的压力.Redis提供了键过期功能,也提供了灵活的键淘汰策略,所以,现在Redis用在缓存的场合非 ...

  5. SpringBoot进阶教程(六十五)自定义注解

    在上一篇文章<SpringBoot进阶教程(六十四)注解大全>中介绍了springboot的常用注解,springboot提供的注解非常的多,这些注解简化了我们的很多操作.今天主要介绍介绍 ...

  6. SpringBoot进阶教程(七十四)整合ELK

    在上一篇文章<SpringBoot进阶教程(七十三)整合elasticsearch >,已经详细介绍了关于elasticsearch的安装与使用,现在主要来看看关于ELK的定义.安装及使用 ...

  7. SpringBoot进阶教程(二十二)集成RabbitMQ---MQ实战演练

    RabbitMQ是一个在AMQP基础上完成的,可复用的企业消息系统.他遵循Mozilla Public License开源协议.RabbitMQ是流行的开源消息队列系统,用erlang语言开发.Rab ...

  8. SpringBoot进阶教程(二十七)整合Redis之分布式锁

    在之前的一篇文章(<Java分布式锁,搞懂分布式锁实现看这篇文章就对了>),已经介绍过几种java分布式锁,今天来个Redis分布式锁的demo.redis 现在已经成为系统缓存的必备组件 ...

  9. SpringBoot进阶教程(六十四)注解大全

    在Spring1.x时代,还没出现注解,需要大量xml配置文件并在内部编写大量bean标签.Java5推出新特性annotation,为spring的更新奠定了基础.从Spring 2.X开始spri ...

随机推荐

  1. JavaScript匿名自执行函数~function(){}

    原博客:https://blog.csdn.net/yaojxing/article/details/72784774 1.匿名函数的常见场景 js中的匿名函数是一种很常见的函数类型,比较常见的场景: ...

  2. JS中sessionstorage的getItem/setItem/removeItem/clear

    function people(){ } var animal = { name: "cc", age:16, say:function(m1,m2){ alert("他 ...

  3. JavaScript高级程序设计(一)

    一.三种常见的著名的命名规则: 1.Camel(驼峰式命名):首字母是小写的,接下来的单词都以大写字母开头.例如:var  myTestValue=0; 2.Pascal(帕斯卡命名):首字母是大写的 ...

  4. SpringCloud实战-Ribbon客户端负载均衡

    前面我们已经完成了注册中心和服务提供者两个基础组件.接着介绍使用Spring Cloud Ribbon在客户端负载均衡的调用服务. ribbon 是一个客户端负载均衡器,可以简单的理解成类似于 ngi ...

  5. cxf webservice生成客户端代码及调用服务端遇到的问题

    1.  从网上下载cxf开发的工具 apache-cxf-3.1.4.zip, 解压文件,找到apache-cxf-3.1.4\bin目录,里面包含一个wsdl2java文件 2. 设置环境变量 1. ...

  6. 最近面了不少java开发,据此来说下我的感受:哪怕事先只准备1小时,成功概率也能大大提升

    本人最近几年一直在做java后端方面的技术面试官,而在最近两周,又密集了面试了一些java初级和高级开发的候选人,在面试过程中,我自认为比较慎重,遇到问题回答不好的候选人,我总会再三从不同方面提问,只 ...

  7. Java程序算法设计视频分享,需要的来

    每年都会有人说,IT行业饱和了,根本就找不到工作,其实,我想说的是,不是工作难找,而是你自己不够好! 前几天看到一CEO在微博上吐槽: 前几天招一算法工程师我们给了8万月薪*14+奖金,人家去阿里拿5 ...

  8. ELK 架构之 Logstash 和 Filebeat 安装配置

    上一篇:ELK 架构之 Elasticsearch 和 Kibana 安装配置 阅读目录: 1. 环境准备 2. 安装 Logstash 3. 配置 Logstash 4. Logstash 采集的日 ...

  9. 【转及总结】Bootstrap 框架 栅格布局系统底层设计原理

    如果你是初次接触Bootstrap,你一定会为它的栅格布局感到敬佩.事实上,这个布局系统提供了一套响应式的布局解决方案. 既然这么好用,那他是如何用CSS来实现的呢? 我特意去Bootstrap官方下 ...

  10. 线程池ThreadPoolExecutor类的使用

    1.使用线程池的好处? 第一:降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗. 第二:提高响应速度.当任务到达时,任务可以不需要等到线程创建就能立即执行. 第三:提高线程的可管理性 ...