Mybatis的缓存机制引发的问题

Mybatis的缓存机制引发的问题解析

最近我参与了一个图像识别的项目,并且遇到了一个奇怪的Bug。通过反复的调试,我才发现问题的根源在于Mybatis的缓存机制。在此文章中,我将向大家分享这段代码以及我的处理方法。

代码说明及问题分析

下面的代码是核心逻辑,使用aiQueueService这个类来查询数据表中是否还有未识别的数据(status=0)。如果没有,就结束while循环;如果有,就把数据更新为已识别(status=1)。

// 代码块1
while (flag) {
    log.info("循环获取queue数据...");
    queue = aiQueueService.getOne(new QueryWrapper<AiQueue>()
            .eq("status",0)
            .last("limit 1"));
    if (queue == null) {
        queueFlag = false;
        DATASTATUS = false;
        log.info("系统无可识别数据");
        break;
    }
    queueFlag = aiQueueService.update(new UpdateWrapper<AiQueue>()
            .eq("id", queue.getId())
            .eq("time_stamp", queue.getTimeStamp())
            .set("status", 1)
            .set("time_Stamp", System.currentTimeMillis())
            .set("update_time", LocalDateTime.now()));
    flag = !queueFlag;
}

处理并不简单,一旦出了问题就需要复杂的调试。经过分析,我们发现,如果数据表中有10条未识别的数据,那么这段代码将会一直无限循环,直到所有的10条数据被更新为已识别。但是,如果每次调用aiQueueService.getOne方法的查询间隔太短,就会触发Mybatis的缓存机制。换句话说,由于短时间内多次查询条件相同,查询的内容并不是从数据表中获取,而是从缓存中获取,这样就会导致代码一直循环下去。

解决方案

在指定的查询方法上添加useCache="false"和flushCache=“true”。这样就不再查询缓存,每次查询都会直接从数据表中获取最新的数据。

<!-- 代码块2 -->
<select id="getOne" resultMap="BaseResultMap" useCache="false" flushCache="true">
    select * from ai_queue 
</select>

小结

好了下面让我们进一步补充一下相关的Mybatis缓存机制知识:

Mybatis中的缓存机制是为了提高SQL查询效率而存在的。当我们执行一条SQL语句时,如果查询的结果有改变,需要重新查询数据库获取最新数据,这样就会降低查询速度,影响性能。而Mybatis的缓存机制会将SQL查询的结果缓存到内存中,下次查询时直接从缓存中读取,如果缓存中没有数据或者数据过期,才会重新查询数据库获取最新数据。这样就能提高查询效率并减轻数据库压力。

Mybatis的缓存机制分为一级缓存和二级缓存。一级缓存是SqlSession级别的缓存,开启一级缓存是Mybatis默认的行为。在同一个SqlSession中(读写操作在同一个事务中),多次查询同一个SQL,只会发送一次SQL语句到数据库,查询结果存储在一级缓存中。一级缓存是基于PerpetualCache的本地缓存,即存储在当前SqlSession对象中,当该SqlSession对象关闭或执行了更新操作(例如增删改)后,一级缓存也会被清空。

二级缓存是Mapper级别的缓存。需要手动开启,在Mapper.xml中声明。二级缓存是基于CachingExecutor的本地缓存,即不同的SqlSession对象可以共享同一个Mapper.xml中的缓存,缓存的作用范围为同一个Mapper.xml文件中的所有SQL语句。二级缓存的存储方式可以是内存,也可以是文件以及其他外部存储方式,缓存时间长度也可以自定义。

需要注意的是,在使用多表关联查询的情况下,Mybatis缓存会出现许多意想不到的问题,例如多表关联查询数据修改后缓存的不一致等问题。如果遇到此类问题,我们需要根据实际情况来选择开启或者关闭Mybatis缓存机制,并且明确不同场景下的各种缓存的作用范围及实现方式。

通过这种特殊的技术处理可以避免程序出现这种奇怪的Bug。如此简单又有效的解决方案,在我的项目中发挥了非常重要的作用,希望这篇文章能够帮助各位同学们。谢谢阅读~

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

格林希尔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值