SpringBoot系列——cache缓存
ztj100 2024-12-03 20:00 27 浏览 0 评论
前言
日常开发中,缓存是解决数据库压力的一种方案,通常用于频繁查询的数据,例如新闻中的热点新闻,本文记录springboot中使用cache缓存。
官方文档介绍:https://docs.spring.io/spring-boot/docs/2.1.0.RELEASE/reference/htmlsingle/#boot-features-caching-provider-generic
工程结构
代码编写
pom引入依赖,引入cache缓存,数据库使用mysql,ORM框架用jpa
<!--添加springdata-cache依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!-- 引入ehcache支持 -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<!--添加springdata-jpa依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!--添加MySQL驱动依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
配置文件
server.port=10010
spring.application.name=springboot-cache
spring.cache.type=ehcache
spring.cache.ehcache.config=classpath:/ehcache.xml
ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd" updateCheck="false">
<!-- 磁盘缓存位置 -->
<diskStore path="java.io.tmpdir"/>
<!-- maxEntriesLocalHeap:堆内存中最大缓存对象数,0没有限制 -->
<!-- maxElementsInMemory: 在内存中缓存的element的最大数目。-->
<!-- eternal:elements是否永久有效,如果为true,timeouts将被忽略,element将永不过期 -->
<!-- timeToIdleSeconds:发呆秒数,发呆期间未访问缓存立即过期,当eternal为false时,这个属性才有效,0为不限制 -->
<!-- timeToLiveSeconds:总存活秒数,当eternal为false时,这个属性才有效,0为不限制 -->
<!-- overflowToDisk: 如果内存中数据超过内存限制,是否要缓存到磁盘上 -->
<!-- statistics:是否收集统计信息。如果需要监控缓存使用情况,应该打开这个选项。默认为关闭(统计会影响性能)。设置statistics="true"开启统计 -->
<!--
默认缓存
无过期时间,但 600 秒内无人访问缓存立即过期
-->
<defaultCache
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="600"
timeToLiveSeconds="0"
overflowToDisk="false">
</defaultCache>
<!--
xx业务缓存
在有效的 120 秒内,如果连续 60 秒未访问缓存,则缓存失效。
就算有访问,也只会存活 120 秒。
-->
<cache name="myCache"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="0"
overflowToDisk="false">
</cache>
</ehcache>
先写一个套tb_user表的CRUD代码
@RestController
@RequestMapping("/tbUser/")
public class TbUserController {
@Autowired
private TbUserService tbUserService;
//方便测试暂时改成GetMapping
@GetMapping("list")
// @PostMapping("list")
public List<TbUser> list(TbUser entityVo) {
return tbUserService.list(entityVo);
}
@GetMapping("get/{id}")
public TbUser get(@PathVariable("id")Integer id) {
return tbUserService.get(id);
}
//方便测试暂时改成GetMapping
@GetMapping("save")
// @PostMapping("save")
public TbUser save(TbUser entityVo) {
return tbUserService.save(entityVo);
}
@GetMapping("delete/{id}")
public Integer delete( @PathVariable("id") Integer id) {
return tbUserService.delete(id);
}
}
opjo实体类要实现序列化
@Entity
@Table(name = "tb_user")
@Data
public class TbUser implements Serializable {
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
private Integer id;//表id
private String username;//用户名
private String password;//密码
private Date created;//创建时间
private Integer descriptionId;//关联详情id
}
serviceImpl中,使用注解来开启缓存
@Service
@Transactional
@CacheConfig(cacheNames = {"myCache"})
public class TbUserServiceImpl implements TbUserService{
@PersistenceContext
private EntityManager em;
@Autowired
private TbUserRepository tbUserRepository;
//@Cacheable缓存数据:key为userList,value为返回值List<TbUser>
@Cacheable(key = "'userList'")
@Override
public List<TbUser> list(TbUser entityVo) {
System.out.println("获取list用户列表缓存数据,"+new Date());
return tbUserRepository.findAll(Example.of(entityVo));
}
//@Cacheable缓存数据:key为参数id,value为返回值TbUser
@Cacheable(key = "#id")
@Override
public TbUser get(Integer id) {
System.out.println("获取数据缓存,key:"+id);
Optional<TbUser> optionalE = tbUserRepository.findById(id);
if (!optionalE.isPresent()) {
throw new RuntimeException("ID不存在!");
}
return optionalE.get();
}
//@CachePut缓存新增的或更新的数据到缓存,其中缓存的名称为people,数据的key是person的id
@CachePut(key = "#entityVo.id")
// @CacheEvict从缓存中删除key为参数userList的数据
@CacheEvict(key = "'userList'")
@Override
public TbUser save(TbUser entityVo) {
System.out.println("新增/更新缓存,key:"+entityVo.getId());
//entityVo传啥存啥,会全部更新
return tbUserRepository.save(entityVo);
}
//清空所有缓存
@CacheEvict(allEntries=true)
@Override
public Integer delete(Integer id) {
System.out.println("清空所有缓存");
tbUserRepository.deleteById(id);
return id;
}
}
效果演示
http://localhost:10010/tbUser/save?id=2&username=李四
调用save方法,key为2,value为当前tbUser对象的数据被缓存下来
http://localhost:10010/tbUser/get/2
当我们调用get方法时,直接获取缓存数据,控制台啥也不打印,连serviceImpl的get方法都不进去(可以打断点调试)
http://localhost:10010/tbUser/save?id=2&username=王五
当我们再次调用save方法更新username时,缓存数据也被更新
http://localhost:10010/tbUser/get/2
再次调用get接口,直接返回缓存数据,后台也是方法都不进去,啥也不打印
http://localhost:10010/tbUser/delete/2
调用delete接口,删除数据,同时删除缓存
再次调用get接口,发现缓存数据被清除,查询数据库
http://localhost:10010/tbUser/list
首次调用list接口,key为userList的,value为用户集合数据被缓存下来,再次调用直接返回缓存数据
当调用save接口,数据更新,删除key为userList的缓存,再次调用list时,重新查库并设置缓存
我们配置了缓存发呆时间,当120秒内未使用该缓存,立即过期,一直用就会一直存在
我们先同时访问两个接口list、get,list接口2分钟后再次访问,get接口不能超过2分钟是不是访问一下,结果如预期
PS:原先使用了这个jar包,有报错
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.8.1</version>
</dependency>
后面改成用上面“代码编写”里pom中引的jnet.sf.ehcache下面的ar
后记
缓存除了能缓解数据库压力,还能做用户登录状态控制,例如:用户登录成功后cookie中保存颁发的token令牌设置永不过期,缓存存活时间也设置永不过期,发呆时间设置1天,这样只有用户在1天内有访问缓存接口,那他就可以一直保留登录状态,直至有其他业务将token或者缓存清掉。
springboot使用cache缓存暂时先记录到这,后续有空再进行补充。
代码开源
代码已经开源、托管到我的GitHub、码云:
GitHub:https://github.com/huanzi-qch/springBoot
码云:https://gitee.com/huanzi-qch/springBoot
版权声明
作者:huanzi-qch
出处:https://www.cnblogs.com/huanzi-qch
若标题中有“转载”字样,则本文版权归原作者所有。若无转载字样,本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利.
相关推荐
- 其实TensorFlow真的很水无非就这30篇熬夜练
-
好的!以下是TensorFlow需要掌握的核心内容,用列表形式呈现,简洁清晰(含表情符号,<300字):1.基础概念与环境TensorFlow架构(计算图、会话->EagerE...
- 交叉验证和超参数调整:如何优化你的机器学习模型
-
准确预测Fitbit的睡眠得分在本文的前两部分中,我获取了Fitbit的睡眠数据并对其进行预处理,将这些数据分为训练集、验证集和测试集,除此之外,我还训练了三种不同的机器学习模型并比较了它们的性能。在...
- 机器学习交叉验证全指南:原理、类型与实战技巧
-
机器学习模型常常需要大量数据,但它们如何与实时新数据协同工作也同样关键。交叉验证是一种通过将数据集分成若干部分、在部分数据上训练模型、在其余数据上测试模型的方法,用来检验模型的表现。这有助于发现过拟合...
- 深度学习中的类别激活热图可视化
-
作者:ValentinaAlto编译:ronghuaiyang导读使用Keras实现图像分类中的激活热图的可视化,帮助更有针对性...
- 超强,必会的机器学习评估指标
-
大侠幸会,在下全网同名[算法金]0基础转AI上岸,多个算法赛Top[日更万日,让更多人享受智能乐趣]构建机器学习模型的关键步骤是检查其性能,这是通过使用验证指标来完成的。选择正确的验证指...
- 机器学习入门教程-第六课:监督学习与非监督学习
-
1.回顾与引入上节课我们谈到了机器学习的一些实战技巧,比如如何处理数据、选择模型以及调整参数。今天,我们将更深入地探讨机器学习的两大类:监督学习和非监督学习。2.监督学习监督学习就像是有老师的教学...
- Python 模型部署不用愁!容器化实战,5 分钟搞定环境配置
-
你是不是也遇到过这种糟心事:花了好几天训练出的Python模型,在自己电脑上跑得顺顺当当,一放到服务器就各种报错。要么是Python版本不对,要么是依赖库冲突,折腾半天还是用不了。别再喊“我...
- 神经网络与传统统计方法的简单对比
-
传统的统计方法如...
- 自回归滞后模型进行多变量时间序列预测
-
下图显示了关于不同类型葡萄酒销量的月度多元时间序列。每种葡萄酒类型都是时间序列中的一个变量。假设要预测其中一个变量。比如,sparklingwine。如何建立一个模型来进行预测呢?一种常见的方...
- 苹果AI策略:慢哲学——科技行业的“长期主义”试金石
-
苹果AI策略的深度原创分析,结合技术伦理、商业逻辑与行业博弈,揭示其“慢哲学”背后的战略智慧:一、反常之举:AI狂潮中的“逆行者”当科技巨头深陷AI军备竞赛,苹果的克制显得格格不入:功能延期:App...
- 时间序列预测全攻略,6大模型代码实操
-
如果你对数据分析感兴趣,希望学习更多的方法论,希望听听经验分享,欢迎移步宝藏公众号...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- idea eval reset (50)
- vue dispatch (70)
- update canceled (42)
- order by asc (53)
- spring gateway (67)
- 简单代码编程 贪吃蛇 (40)
- transforms.resize (33)
- redisson trylock (35)
- 卸载node (35)
- np.reshape (33)
- torch.arange (34)
- npm 源 (35)
- vue3 deep (35)
- win10 ssh (35)
- vue foreach (34)
- idea设置编码为utf8 (35)
- vue 数组添加元素 (34)
- std find (34)
- tablefield注解用途 (35)
- python str转json (34)
- java websocket客户端 (34)
- tensor.view (34)
- java jackson (34)
- vmware17pro最新密钥 (34)
- mysql单表最大数据量 (35)