目录
1 作用
2 引入pom
3 开启注解驱动缓存管理
4 配置redis
5 service层使用缓存
5.1 使用@Cacheable&@CacheEvict注解
6 controller层调用
7 验证
对于一些幂等性方法,可以在第一次访问后将返回数据存储在缓存中,这样可避免每次请求都要访问数据库,减少数据库的压力,提高请求响应速度。Spring自身不提供缓存的存储实现,需要借助第三方,比如JCache、EhCache、Hazelcast、Redis、Guava等,Spring Cache作用在方法上时,其思想是:当我们在调用一个缓存方法时会把该方法参数和返回结果作为一个键值对存放在缓存中,等到下次利用同样的参数来调用该方法时将不再执行该方法,而是直接从缓存中获取结果进行返回。在多线程的情况下,Cache底层实现线程安全。本文主要利用spring cache + redis来实现服务请求缓存。
主要引入redis的依赖
org.springframework.boot
spring-boot-starter-data-redis
在启动类中加入@EnableCaching开启缓存
@EnableCaching //加入Spring cache
@SpringBootApplication
public class BookshopConsumerCacheApplication {
public static void main(String[] args) {
SpringApplication.run(BookshopConsumerCacheApplication.class, args);
}
}
在application.yml中配置如下项:
spring:
redis:
database: 1 #Redis数据索引(默认0)
host: 127.0.0.1 #Redis服务器地址
port: 6379 #Redis服务器端口
#password: 123456 #Redis服务器密码,本机未设置,如设置请去掉注释进行修改
pool:
max-active: 100 #连接池最大连接数
max-wait: 3000 #连接池最大阻塞等待时间(负值表示没有限制)
max-idle: 200 #连接池的最大空闲连接数
min-idle: 50 #连接池的最小空闲连接数
timeout: 600 #连接超时时间(毫秒)
cache提供了如下方法:
@Cacheable
应用到读取数据的方法上,即可缓存的方法,如查找方法:先从缓存中读取,如果没有再调用方法获取数据,然后把数据添加到缓存中。
@Cacheable的源码如下:
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Cacheable {
@AliasFor("cacheNames")
String[] value() default {};
@AliasFor("value")
String[] cacheNames() default {};
String key() default "";
String cacheManager() default "";
String cacheResolver() default "";
String condition() default "";
String unless() default "";
boolean sync() default false;
}
需要说明的是:Cache缓存时,如果多个同时调用,当内存中没有命中key的时候,会直接调用方法计算,这会导致重复计算,以及缓存没有生效,这时就需要采用同步的方式,一个方法调用,其余的在等待。只需设置sync=true即可。
@CacheEvict
即应用到移除数据的方法上,如删除方法,调用方法时会从缓存中移除相应的数据。
@CachePut
应用到写数据的方法上,如新增/修改方法,调用方法时会自动把相应的数据放入缓存。
@Cacheable和@CachePut的区别:
@Cacheable:当重复使用相同参数调用方法的时候,方法本身不会再被调用执行,方法的结果直接从缓存中找到并返回。
@CachePut:这个注释可以确保方法每次被执行,同时方法的返回值也被记录到缓存中。
两个注解可以结合使用,当同样的参数需要根据请求改变值的时候,利用@CachePut将值改变并写入到缓存中,而@Cacheable标签除了第一次之外,一直是取的缓存的值(缓存中有对应的key)。
结合使用时需要注意两点:
1、必须是同一个缓存实例。
2、key值必须是相同的。
在service层实现向redis中存储读取,删除数据。
@CacheConfig(cacheNames={"com.book"}) //配置了该数据访问对象中返回的内容将存储于名为com.book的缓存对象中
@Service
public class BookService {
@Cacheable(key="'book'+#id")
public Book getBook(Integer id) {
System.out.println("===get book== "+ id+"==");
Book book = new Book();
book.setId(id);
book.setBookName("redis + spring cache");
book.setAuthor("xxx");
return book;
}
@CacheEvict(key="'book'+#id")
public void del(Integer id) {
//删除redis中的数据
System.out.println("====del book== " + id+"===");
}
}
@RestController
public class BookController {
@Autowired
private BookService bookservice;
@RequestMapping(value="/get/{id}",method=RequestMethod.GET)
public Book getBook(@PathVariable("id") Integer id) {
return bookservice.getBook(id);
}
@RequestMapping(value="/del/{id}",method=RequestMethod.GET)
public void delBook(@PathVariable("id") Integer id){
bookservice.del(id);
}
}
运行启动类,分别访问http://127.0.0.1:8080/get/1 和 http://127.0.0.1:8080/get/2 后,在redis中可以查看
redis 127.0.0.1:6379>
redis 127.0.0.1:6379> select 1
OK
redis 127.0.0.1:6379[1]> keys * //访问前未写入数据
(empty list or set)
redis 127.0.0.1:6379[1]> keys * //访问后写入数据
1) "com.book::book1"
2) "com.book::book2"
redis 127.0.0.1:6379[1]>
访问http://127.0.0.1:8080/del/1后,删除reidis中key为book1的值,在redis中查看,结果如下:
redis 127.0.0.1:6379[1]>
redis 127.0.0.1:6379[1]> keys *
1) "com.book::book2"
redis 127.0.0.1:6379[1]>