Spring Boot基础学习之Mybatis操作中使用Redis做缓存详解
前言
这篇博客学习下mybatis操作中使用redis做缓存。这里其实主要学习几个注解:@cacheput、@cacheable、@cacheevict、@cacheconfig。
下面话不多说了,来一起看看详细的介绍吧
一、基础知识
@cacheable
@cacheable 的作用 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存
参数 | 解释 | example |
---|---|---|
value | 缓存的名称,在 spring 配置文件中定义,必须指定至少一个 | 例如: @cacheable(value=”mycache”) @cacheable(value={”cache1”,”cache2”} |
key | 缓存的 key,可以为空,如果指定要按照 spel 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 | @cacheable(value=”testcache”,key=”#username”) |
condition | 缓存的条件,可以为空,使用 spel 编写,返回 true 或者 false,只有为 true 才进行缓存 | @cacheable(value=”testcache”,condition=”#username.length()>2”) |
@cacheput
@cacheput 的作用 主要针对方法配置,能够根据方法的返回值对其结果进行缓存,和 @cacheable 不同的是,它每次都会触发真实方法的调用,在其他地方写的是根据方法的请求参数对其结果进行缓存,实际是按方法返回值进行缓存的,这里我就遇到了一个坑,我开始的时候是在mybatis的mapper层进行缓存的,如下面的代码。但是缓存到redis的是null值,今天看了一博友的博客,交流了一下,才知道它缓存的是方法的返回值,如果把下面update的返回值该为int,在redis中保存的是int类型,报的错误是int无法转换成user对象。
@cacheput(value="user",key = "#p0.id") @update({"update user set name=#{name},age=#{age} where id =#{id}"}) void update(user user);
参数 | 解释 | example |
---|---|---|
value | 缓存的名称,在 spring 配置文件中定义,必须指定至少一个 | @cacheput(value=”my cache”) |
key | 缓存的 key,可以为空,如果指定要按照 spel 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 | @cacheput(value=”testcache”,key=”#username”) |
condition | 缓存的条件,可以为空,使用 spel 编写,返回 true 或者 false,只有为 true 才进行缓存 | @cacheput(value=”testcache”,condition=”#username.length()>2”) |
@cachevict
@cachevict 的作用 主要针对方法配置,能够根据一定的条件对缓存进行清空
参数 | 解释 | example |
---|---|---|
value | 缓存的名称,在 spring 配置文件中定义,必须指定至少一个 | @cacheevict(value=”my cache”) |
key | 缓存的 key,可以为空,如果指定要按照 spel 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 | @cacheevict(value=”testcache”,key=”#username”) |
condition | 缓存的条件,可以为空,使用 spel 编写,返回 true 或者 false,只有为 true 才进行缓存 | @cacheevict(value=”testcache”,condition=”#username.length()>2”) |
allentries | 是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存 | @cachevict(value=”testcache”,allentries=true) |
beforeinvocation | 是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存 | @cachevict(value=”testcache”,beforeinvocation=true) |
@cacheconfig
所有的@cacheable()里面都有一个value=“xxx”的属性,这显然如果方法多了,写起来也是挺累的,如果可以一次性声明完 那就省事了,有了@cacheconfig这个配置,@cacheconfig is a class-level annotation that allows to share the cache names,如果你在你的方法写别的名字,那么依然以方法的名字为准。
二、实例
还是在上一博客demo的基础上进行修改,原本是在mybatis的mapper层上增加cache注解,但由于update返回值为void,所以这里又增加了一services层,mapper层算是dao层。这里使用了@cacheconfig注解指定类级别的value属性,如果在方法上定义就以方法为主,就近原则。
package com.example.services; import java.util.list; import org.springframework.beans.factory.annotation.autowired; import org.springframework.cache.annotation.cacheconfig; import org.springframework.cache.annotation.cacheevict; import org.springframework.cache.annotation.cacheput; import org.springframework.cache.annotation.cacheable; import org.springframework.stereotype.service; import com.example.model.user; import com.example.write.mapper.writeusermapper; @service @cacheconfig(cachenames="user") public class userservices { @autowired private writeusermapper writeusermapper; public list<user> getall() { return writeusermapper.getall(); } @cacheable(key = "#p0") public user getone(string id) { return writeusermapper.getone(id); } public void insert(user user) { writeusermapper.insert(user); } @cacheput(value="user",key = "#p0.id") public user update(user user) { writeusermapper.update(user); return user; } @cacheevict(value="user",key ="#p0",allentries=true) public void delete(string id) { writeusermapper.delete(id); } }
usercontroller
package com.example.demo; import java.io.serializable; import java.util.list; import javax.servlet.http.httpservletrequest; import javax.servlet.http.httpservletresponse; import org.springframework.beans.factory.annotation.autowired; import org.springframework.data.redis.core.redistemplate; import org.springframework.data.redis.core.stringredistemplate; import org.springframework.stereotype.controller; import org.springframework.ui.model; import org.springframework.web.bind.annotation.pathvariable; import org.springframework.web.bind.annotation.requestmapping; import org.springframework.web.bind.annotation.requestmethod; import org.springframework.web.servlet.modelandview; import com.example.model.user; import com.example.model.usersexenum; import com.example.read.mapper.readusermapper; import com.example.services.userservices; import com.example.write.mapper.writeusermapper; import io.lettuce.core.dynamic.annotation.param; @controller @requestmapping("/user") public class usercontroller { @autowired private writeusermapper usermapperwrite; @autowired private readusermapper usermapperread; @autowired private stringredistemplate stringredistemplate; @autowired private redistemplate<string, serializable> rediscachetemplate; @autowired private userservices userservices; @requestmapping(value = "/alluser.do",method = requestmethod.get) public string getallusers(model model) { list<user> users=userservices.getall(); model.addattribute("users", users); // stringredistemplate.opsforvalue().set("keytest", "cuiyw"); // final string keytest = stringredistemplate.opsforvalue().get("keytest"); // model.addattribute("keytest", keytest); // string key = "1857xxxx040"; // rediscachetemplate.opsforvalue().set(key, new user(key, "cuiyw", 18, usersexenum.man)); // // todo 对应 string(字符串) // final user user = (user) rediscachetemplate.opsforvalue().get(key); // model.addattribute("user", user); return "userlist"; } @requestmapping(value = "/insert.do",method = requestmethod.get) public string adduser(model model) { user user=new user(); user.setname("cuiyw"); user.setage(27); userservices.insert(user); // list<user> users=usermapperwrite.getall(); // model.addattribute("users", users); return "forward:/user/alluser.do"; } @requestmapping(value = "/getuserbyid.do/{id}",method = requestmethod.get) public modelandview getuserbyid(@pathvariable("id") string id) { system.out.println(id); user user=userservices.getone(id); system.out.println(user.tostring()); modelandview modelandview = new modelandview("userlist"); modelandview.addobject("user", user); return modelandview; } @requestmapping(value = "/deleteuserbyid.do/{id}",method = requestmethod.get) public string deleteuserbyid(@pathvariable("id") string id) { userservices.delete(id); return "forward:/user/alluser.do"; } @requestmapping(value = "/updateuserbyid.do/{id}",method = requestmethod.get) public string updateuserbyid(@pathvariable("id") string id) { user user=userservices.getone(id); system.out.println(user.tostring()); user.setage(28); system.out.println(user.tostring()); userservices.update(user); system.out.println(user.tostring()); return "forward:/user/alluser.do"; } }
这里先输入http://localhost:8080/user/getuserbyid.do/17通过getone()方法在redis中缓存一个user。通过redis-cli可以看到user::17已在redis中。
然后通过update()方法输入http://localhost:8080/user/updateuserbyid.do/17修改user,此时年龄改为了28,数据库的值也会变了。然后多次使用http://localhost:8080/user/updateuserbyid.do/17这个url刷新浏览器,此时是不会报错的,如果是在mapper中使用@cacheput时由于保存的是null就会导致报错。
最后通过delete()方法输入http://localhost:8080/user/deleteuserbyid.do/17删除redis和数据库中的user对象.
至此,基本把这4个注解大致了解了一下,这里还有一个地方需要补充,就是如果按照上面运行还是不行的,它依然找不到userservices,在usercontroller中找不到这个类,还需要在main方法上面@componentscan注解加上扫描com.example.services。
@componentscan(basepackages={"com.example.config","com.example.demo","com.example.services"})
最后来一碗鸡汤,记录下今天看抖音听到的一句话,还挺有道理。
为什么大多数人宁愿吃生活的苦,而不愿意吃学习的苦?因为学习的苦需要自己主动去吃,而生活的苦你躺着它就来了。
总结:
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。
下一篇: Java程序员应该遵守的10条纪律