给查询业务添加redis缓存和缓存更新策略

目录

一、添加redis缓存的主要逻辑

二、代码

三、结果

四、缓存更新策略

五、代码


一、添加redis缓存的主要逻辑

在未添加缓存时,前端向后端发起查询请求时,后端收到请求就直接查数据库,它的速度如下:

其实速度也不慢,那是因为我的数据库里面没有太多数据,所以查起来速度还是特别快的,但随着我们的数据库数据量逐渐增大,如果没有缓存的话,那查询速度会越来越慢。

添加redis缓存的逻辑也不难,总结下来也就是以下这几点:

1.后端查询时,先查redis缓存,redis缓存中有数据直接返回,没有数据再去查数据库

2.查数据库时,没有对应数据则向前端发出错误信息,有数据则向前端发送数据并将数据写入redis缓存中

流程图如下所示:

二、代码

java 复制代码
@Service
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    /**
     * 根据id查询店铺信息
     * @param id
     * @return
     */
    @Override
    public Result queryById(Long id) {
        String key = RedisConstants.CACHE_SHOP_KEY + id;
        //1.从redis中查询商铺缓存信息
        String shopJson = stringRedisTemplate.opsForValue().get(key);
        //2、判断是否存在
        if (StrUtil.isNotBlank(shopJson)) {
            //3、存在,直接返回
            Shop shop = JSONUtil.toBean(shopJson, Shop.class);
            return Result.ok(shop);
        }
        //4、不存在,根据id查询数据库
        Shop shop = getById(id);
        //5、判断数据库中是否有数据
        if (shop == null) {
            //6、没有,返回错误
            return Result.fail("店铺不存在");
        }
        //7、有数据,返回,并将数据写入redis
        String jsonStr = JSONUtil.toJsonStr(shop);
        stringRedisTemplate.opsForValue().set(key,jsonStr);
        //8、返回结果
        return Result.ok(shop);
    }
}

三、结果

当第一次执行时,redis中是没有数据的,执行过后就会将对应数据写入redis中

下一次的查询时速度就会快上不少

如果数据库中的数据更多的话,效果会更加明显

四、缓存更新策略

既然我们已经对查询业务增加了缓存,那当数据库的数据和缓存数据不一样的时候,我们如何去解决它们之间的一致性问题呢?

其实解决方案十分简单:

当数据库的数据发生变更时,例如增加、删除、修改等操作,我们先去操作数据库再去删除缓存。

为什么选择删除缓存而不选择更新缓存呢?

如果选择更新缓存很可能会出现多次无效的写操作,比如:我更新了十次数据库之后才有一次查询操作,这时候缓存也是随之更新了十次。那如果我在他第一次更新数据库的时候就选择删除缓存,那么我就省去了这些更新缓存的无效写操作,性能上肯定是提高了不少。因此我们会选择删除缓存而不是更新缓存。

为什么要选择先操作数据库而不是先操作缓存呢?

因为数据库是基于磁盘的,缓存是基于内存的,操作数据库的耗时往往会比操作缓存的耗时大上不少。因此如果先删缓存再更新数据库,那就会出现在更新数据库的过程中(时间比较长)被其他查询缓存的操作乘虚而入,这时候缓存为空会从数据库中拿数据填入缓存,这时候就会出现数据不一致的问题。因此我们会选择先操作数据库再操作缓存。

因此我们还要给上面写的代码进行补全,在对数据进行修改的时候要进行以下的逻辑:

1.更新数据库

2.删除缓存

五、代码

java 复制代码
    @Override
    @Transactional
    public Result update(Shop shop) {
        Long id = shop.getId();
        if (id == null) {
            return Result.fail("店铺id不能为空");
        }
        //1.更新数据库
        updateById(shop);
        //2.删除缓存
        stringRedisTemplate.delete(RedisConstants.CACHE_SHOP_KEY + id);
        //3.返回结果
        return Result.ok();
    }
相关推荐
ttwuai9 分钟前
AI 生成后台删除按钮后,MySQL 软删除和唯一索引怎么验
数据库·mysql·golang
张人玉18 分钟前
基于 Vue 3 + ECharts + Express + SQLite 构建的新能源汽车销量数据分析与可视化平台——新能源汽车销量数据分析系统
数据库·vue.js·sqlite·echarts
2601_9638701720 分钟前
【计算机毕业设计】基于Spring Boot的社区老年大学课程报名与学习系统的设计与实现
java·spring boot·学习
llwszx33 分钟前
【Java/Go后端手撸原生Agent(第七篇):Token预算管理 + 滑动窗口上下文裁剪】
java·后端·python·agent开发·上下文工程·上下文裁剪·滑动窗口裁剪
weixin_BYSJ19871 小时前
springboot3家政平台小程序--附源码00904
java·javascript·spring boot·python·django·flask·php
凤山老林2 小时前
SpringBoot 3 启用 spring.factories 后如何升级替换原有的 spring.factories ?
spring boot·后端·spring
梦幻通灵2 小时前
Java中finally失效的几种情况【持续更新】
java·开发语言
月落归舟2 小时前
SpringMVC 多种响应返回方式
java·开发语言
吃饱了得干活2 小时前
JVM垃圾回收:从新生代到ZGC,从理论到调优
java·jvm·后端
长不胖的路人甲2 小时前
二叉排序树(BST)Java 完整实现 + 删除思路详解
java·开发语言·算法