您的位置:首页 > 编程语言 > Java开发

Spring Boot中缓存注解的配置与使用

2017-08-06 00:00 696 查看

Spring Boot中缓存注解配置与使用

首先是配置

1.在pom文件中加入依赖

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

2.主类上面加注解 @EnableCaching

在application上加 @EnableCaching,用于开启缓存功能

@EnableCaching
public class LgdtstpApplication {

public static void main(String[] args) {
SpringApplication.run(LgdtstpApplication.class, args);
}
}

3.在数据访问接口上,加@CacheConfig(cacheNames = "persons"),方法上加@Cacheable(key = "#id")

@CacheConfig(cacheNames = "persons")注解为Spring4新增,如果不加这个,可以只写@Cacheable(value = "persons",key = "#id")
在加入缓存时以Map形式 @Cacheable中的value参数,等价于@CacheConfig中的cacheNames。 代表Map的名字
key参数代表Map中的键,加入缓存的数据为Map中的value

@CacheConfig(cacheNames = "persons")
public class PersonService {

//查询个人信息
@Cacheable(key = "#id")
public HttpResponseEntity queryPersonInfo(String id) {
HttpResponseEntity httpResponseEntity = new HttpResponseEntity();
String str = "";
//接收查询到的个人信息
PersonInfoEntity entity1= personInfoEntityMapper.selectByPrimaryKey(id);
str = "id是:"+entity1.getId()+"  name是:"+entity1.getName()+"         ";
System.out.println(str);
//用于返回数据
httpResponseEntity.setData(entity1);
return httpResponseEntity;
}

我理解写入缓存的Map

persons:{id:存入的数据}

配置完我们来测试下@Cacheable注解

先看下不加缓存时

正常运行程序 查询id为0的用户

//    @Cacheable(key = "#id")
public HttpResponseEntity queryPersonInfo(String id) {
HttpResponseEntity httpResponseEntity = new HttpResponseEntity();
String str = "";
//接收查询到的个人信息
PersonInfoEntity entity1= personInfoEntityMapper.selectByPrimaryKey(id);
str = "id是:"+entity1.getId()+"  name是:"+entity1.getName()+"         ";
System.out.println(str);
//用于返回数据给postMan
httpResponseEntity.setData(entity1);
return httpResponseEntity;
}

看下控制台

2017-08-06 15:44:57.694 [http-nio-8080-exec-1] DEBUG c.a.l.d.P.selectByPrimaryKey -==>  Preparing: select _id, user_id, name, sex, birth, phone_number, email, skill_tag, credit_score, address, head_pic_url, create_time, modify_time, production_pic_url, video_url,status , introduction from person_info_t where _id = ?

2017-08-06 15:44:57.718 [http-nio-8080-exec-1] DEBUG c.a.l.d.P.selectByPrimaryKey -==> Parameters: 0(String)

2017-08-06 15:44:57.733 [http-nio-8080-exec-1] DEBUG c.a.l.d.P.selectByPrimaryKey -<==      Total: 1
id是:0  name是:铜蛋

执行了1次查询语句 ,输出数据信息,看看postMan中的返回结果

{
"code": null,
"data": {
"id": "0",
"userId": "0",
"name": "铜蛋",

接下来我们去数据库中修改name为铁蛋
在执行一次查询,控制台信息如下

2017-08-06 15:44:57.694 [http-nio-8080-exec-1] DEBUG c.a.l.d.P.selectByPrimaryKey -==>  Preparing: select _id, user_id, name, sex, birth, phone_number, email, skill_tag, credit_score, address, head_pic_url, create_time, modify_time, production_pic_url, video_url,status , introduction from person_info_t where _id = ?

2017-08-06 15:44:57.718 [http-nio-8080-exec-1] DEBUG c.a.l.d.P.selectByPrimaryKey -==> Parameters: 0(String)
2017-08-06 15:44:57.733 [http-nio-8080-exec-1] DEBUG c.a.l.d.P.selectByPrimaryKey -<==      Total: 1
id是:0  name是:铜蛋

2017-08-06 15:57:07.351 [http-nio-8080-exec-5] DEBUG c.a.l.d.P.selectByPrimaryKey -==>  Preparing: select _id, user_id, name, sex, birth, phone_number, email, skill_tag, credit_score, address, head_pic_url, create_time, modify_time, production_pic_url, video_url,status , introduction from person_info_t where _id = ?

2017-08-06 15:57:07.351 [http-nio-8080-exec-5] DEBUG c.a.l.d.P.selectByPrimaryKey -==> Parameters: 0(String)
2017-08-06 15:57:07.354 [http-nio-8080-exec-5] DEBUG c.a.l.d.P.selectByPrimaryKey -<==      Total: 1
id是:0  name是:铁蛋

postMan返回信息为

{
"code": null,
"data": {
"id": "0",
"userId": "0",
"name": "铁蛋",

总结一下,两次查询,执行两次语句,操作两次数据库,当数据库中name值变化的时候,返回的结果为修改后的name值

接下来加上缓存

@Cacheable(key = "#id")
public HttpResponseEntity queryPersonInfo(String id) {
HttpResponseEntity httpResponseEntity = new HttpResponseEntity();
String str = "";
//接收查询到的个人信息
PersonInfoEntity entity1= personInfoEntityMapper.selectByPrimaryKey(id);
str = "id是:"+entity1.getId()+"  name是:"+entity1.getName()+"         ";
System.out.println(str);
//用于返回数据
httpResponseEntity.setData(entity1);
return httpResponseEntity;
}

运行第一次查询,查询id为0的用户信息,控制台输出信息如下

2017-08-06 16:03:33.956 [http-nio-8080-exec-1] DEBUG c.a.l.d.P.selectByPrimaryKey -==>  Preparing: select _id, user_id, name, sex, birth, phone_number, email, skill_tag, credit_score, address, head_pic_url, create_time, modify_time, production_pic_url, video_url,status , introduction from person_info_t where _id = ?

2017-08-06 16:03:33.979 [http-nio-8080-exec-1] DEBUG c.a.l.d.P.selectByPrimaryKey -==> Parameters: 0(String)
2017-08-06 16:03:33.995 [http-nio-8080-exec-1] DEBUG c.a.l.d.P.selectByPrimaryKey -<==      Total: 1
id是:0  name是:铁蛋

postMan中返回的信息如下

{
"code": null,
"data": {
"id": "0",
"userId": "0",
"name": "铁蛋",

接下来我们去数据库中修改name值,把铁蛋改为铜蛋,再次执行查询,看看控制台(此处划重点)

2017-08-06 16:03:33.956 [http-nio-8080-exec-1] DEBUG c.a.l.d.P.selectByPrimaryKey -==>  Preparing: select _id, user_id, name, sex, birth, phone_number, email, skill_tag, credit_score, address, head_pic_url, create_time, modify_time, production_pic_url, video_url,status , introduction from person_info_t where _id = ?

2017-08-06 16:03:33.979 [http-nio-8080-exec-1] DEBUG c.a.l.d.P.selectByPrimaryKey -==> Parameters: 0(String)
2017-08-06 16:03:33.995 [http-nio-8080-exec-1] DEBUG c.a.l.d.P.selectByPrimaryKey -<==      Total: 1
id是:0  name是:铁蛋

这时发现只有第一次查询时输出的信息,刚刚更改数据库后执行的查询,根本没有输出,来看下postMan

{
"code": null,
"data": {
"id": "0",
"userId": "0",
"name": "铁蛋",

返回的结果还是铁蛋,可我们刚才修改数据库中的name值,明明把铁蛋改为了铜蛋,为什么返回的还是铁蛋呢?
这是因为注解@Cacheable(key = "#id")的作用,当调用标注的方法时会先查看缓存中是否有数据
如果有数据,则直接返回缓存数据;若没有数据,执行该方法并将方法返回值放进缓存。
所以我们第二次查询实际上根本没有去查询数据库,而是将第一次查询存入的缓存返了回来,这样就减少了对操作数据库的压力。
但问题依然存在,数据库中的值变更了,但返回的依然是变更前的数据,造成了数据不同步,这要怎么解决呢?我们可以用另一个注解去处理这个问题。

@CachePut注解的应用

刚刚我们是直接在数据库中修改了name值,这次我们调用一个带有@CachePut注解的方法,@CachePut注解的作用和Cacheable相似,只是带有@CachePut注解的方法在执行后,会将返回值存入缓存中。也就是说当我修改了数据库,就把修改后返回的值放入缓存中,相当于刷新了之前的缓存。要注意的是,@CachePut中key参数的值要和@Cacheable中的key对应上,这样才能保证数据被放入Map中同一个Key对应的value中

调用修改姓名的方法,将姓名改为彩蛋

//修改个人基本信息
@CachePut(key = "#personInfoEntity.id")
public HttpResponseEntity alterBasicInfomation(PersonInfoEntity personInfoEntity) {
HttpResponseEntity httpResponseEntity = new HttpResponseEntity();
logger.info("修改个人基本资料");
Date nowDate = new Date();
personInfoEntity.setModifyTime(nowDate);
int number = personInfoEntityMapper.updateByPrimaryKeySelective(personInfoEntity);
if (number != -1) {
logger.info("修改个人基本资料成功");
httpResponseEntity.setCode(Constans.SUCCESS_CODE);
} else {
logger.info("修改个人基本资料失败");
httpResponseEntity.setCode(Constans.ALTER_BASIC_INFOMATION_ERROR_CODE);
httpResponseEntity.setMessage(Constans.ALTER_BASIC_INFOMATION_ERROR_CMESSAGE);
}
//修改后查询该条信息,将修改后的数据同步给缓存和前端
PersonInfoEntity personInfoEntity1 = personInfoEntityMapper.selectByPrimaryKey(personInfoEntity.getId());
httpResponseEntity.setData(personInfoEntity1);
//返回修改后的数据,返回的结果会被CachePut放入缓存,同步数据
return httpResponseEntity;
}

修改成功,
再次执行查询,控制台依然没有执行语句操作数据库,而是直接从缓存中读取了,postMan中返回数据如下

{
"code": "200",
"data": {
"id": "0",
"userId": "0",
"name": "彩蛋",

读取数据为修改后的数据,同步成功。

总结:当调用带有@CachePut注解的方法时,总是会执行该方法,并且把返回的结果同步给缓存,查询的时候,因为缓存中的数据被同步了,所以就不会造成数据被修改,但查询的还是之前数据这种bug。

最后放上注解详解,方便以后查看

@CacheConfig:主要用于配置该类中会用到的一些共用的缓存配置。在这里@CacheConfig(cacheNames = "users"):配置了该数据访问对象中返回的内容将存储于名为users的缓存对象中,我们也可以不使用该注解,直接通过@Cacheable自己配置缓存集的名字来定义。

@Cacheable:配置了findByName函数的返回值将被加入缓存。同时在查询时,会先从缓存中获取,若不存在才再发起对数据库的访问。该注解主要有下面几个参数:

value、cacheNames:两个等同的参数(cacheNames为Spring 4新增,作为value的别名),用于指定缓存存储的集合名。由于Spring 4中新增了@CacheConfig,因此在Spring 3中原本必须有的value属性,也成为非必需项了

key:缓存对象存储在Map集合中的key值,非必需,缺省按照函数的所有参数组合作为key值,若自己配置需使用SpEL表达式,比如:@Cacheable(key = "#p0"):使用函数第一个参数作为缓存的key值,更多关于SpEL表达式的详细内容可参考官方文档

condition:缓存对象的条件,非必需,也需使用SpEL表达式,只有满足表达式条件的内容才会被缓存,比如:@Cacheable(key = "#p0", condition = "#p0.length() < 3"),表示只有当第一个参数的长度小于3的时候才会被缓存。

unless:另外一个缓存条件参数,非必需,需使用SpEL表达式。它不同于condition参数的地方在于它的判断时机,该条件是在函数被调用之后才做判断的,所以它可以通过对result进行判断。

keyGenerator:用于指定key生成器,非必需。若需要指定一个自定义的key生成器,我们需要去实现org.springframework.cache.interceptor.KeyGenerator接口,并使用该参数来指定。需要注意的是:该参数与key是互斥的

cacheManager:用于指定使用哪个缓存管理器,非必需。只有当有多个时才需要使用

cacheResolver:用于指定使用那个缓存解析器,非必需。需通过org.springframework.cache.interceptor.CacheResolver接口来实现自己的缓存解析器,并用该参数指定。

@CachePut:配置于函数上,能够根据参数定义条件来进行缓存,它与@Cacheable不同的是,它每次都会真是调用函数,所以主要用于数据新增和修改操作上。它的参数与@Cacheable类似,具体功能可参考上面对@Cacheable参数的解析

@CacheEvict:配置于函数上,通常用在删除方法上,用来从缓存中移除相应数据。除了同@Cacheable一样的参数之外,它还有下面两个参数:

allEntries:非必需,默认为false。当为true时,会移除所有数据

beforeInvocation:非必需,默认为false,会在调用方法之后移除数据。当为true时,会在调用方法之前移除数据。

注解详解出自:http://www.jianshu.com/p/64f684bd0ce9,里面还有关于EhCacheManager的配置。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: