Redis优化Spring项目的数据库读写
使用Redis做缓存,简单优化软件工程实践课的MySql读写的性能
前言
醋来了!前面对Redis的学习就是为了优化一下一个完整的SpringBoot+MySql项目的数据库搜索的性能,使用Redis作为MySql数据库的缓存使用,优化高频读取操作的性能,以及涉及多表查询的结果的缓存(减小服务器负担)。
优化思路
本质上就是非常经典的缓存模型,客户端对一些高频接口或高搜索复杂度接口进行请求时,在后端将请求先引导到对Redis的访问,若请求命中(Redis存有对应的数据),则直接返回给客户端该数据,若未命中(Redis返回结果为空),则按照正常流程访问MySql等主数据库,并在返回结果前向Redis写入该数据(并设置过期时间),以便下次访问。

具体案例
案例代码来自软件工程专业课《软件工程综合实践》的Vue3+SpringBoot+MySql的项目。
这里选择一个涉及多表查询的查询性能较差的搜索:
1 |
|
具体实现还是非常简单的,接下来简单测试一下性能。
性能测试
因为是课程设计的小项目,数据量没有多大,只是相对的对比一下采用Redis做缓存和不用时在ApiFox上的响应速度。
在ApiFox上对接口对应的方法getOrderById进行100次测试,结果如下:
使用Redis作为缓存的100次访问测试:

未使用Redis作为缓存的100次访问测试:

测试结论
可见二者有着较大的性能差异,并且随着查询接口对数据库搜索数据规模的增大,不使用缓存机制的搜索时间还将上升,而使用Redis作为缓存本质上就是对一个键值对进行简单的读取,除了第一次的未命中外,此后的缓存访问都将以较快的速度进行。
此外针对高热度的访问接口,缓存机制也将持续保留并刷新其过期时间,本质上是对高负载接口的读写优化。
那么代价是什么呢?
数据库缓存不一致
缓存是写入Redis了,如果在其过期时间内又有在MySql对其相关数据进行了操作,导致MySql上的对应数据和Redis上的不一致,此时Redis上存的不就是错误数据了吗?
此时的解决方法就是,在后端的涉及Redis存储的数据的类的操作,也是不仅仅要更新MySql,也要”更新“Redis(如果有)。
1 |
|
删除缓存还是更新缓存
在对缓存数据进行更新时有两个选择:
更新缓存:找到对应的key,更新其value
删除缓存:直接删除对应key的键值对数据,等待下一次访问时再将数据写入缓存
通常会先更新数据库再删除缓存,而不是直接更新缓存,原因如下:
1.简单直接:代码逻辑清晰,不易出错。
2.避免并发写问题:在多个线程/服务同时更新同一个数据时,无论操作顺序如何,最终都会通过删除缓存来保证下次读取到最新数据。它避免了“更新顺序”竞态条件(后面会详述)。
3.处理复杂数据:如果缓存的数据是经过复杂计算或聚合(如多个表的JOIN结果),更新缓存时需要重复这个复杂计算。而删除缓存则把计算延迟到下次读取时,逻辑更清晰。
4.写操作轻量:写操作只需要处理数据库,无需关心缓存数据的构建,性能更好。
先操作缓存还是先操作数据库
推荐先操作数据库,再操作缓存,出现不一致的概率远低于先操作缓存再更新数据库。
具体原因涉及多线程相关,可以自行了解。