Mybaiys源码赏析一:可以优化的查询方法

1.知识铺垫:

首先我们要了解Mybaits的缓存机制,一级缓存默认是SESSION级别的,所有的查询都是先查询一级缓存没有的话再去查询数据库,而且一级缓存不能关闭,二级缓存是默认不开启的,是mapper级别的,相同的namespace共用一个缓存(比较鸡肋),一般用redis去代替二级缓存。


2.问题描述及原因分析:

好了,咱们言归正传,直接上源码:
在这里插入图片描述
我给大家解释一下这段代码的含义就是判断resultHadnler等于null的情况下先从localCache里面根据key查询值,如果查询到了执行handleLocallyCachedOutputParameters()方法,这个方法主要是跟存储过程相关,一般用不到,重点来了!!!请看下面的图
在这里插入图片描述
在这里插入图片描述

这里往localCache里面,以key作为key存入了EXECUTION_PLACEHOLDER一个枚举值,如果两个线程同时执行这段逻辑的话,第一个线程到了doQuery()方法耗时比较久,迟迟没有执行localCache.removeObject(key);将key删除的话,那么第二个线程到达判断第一张图的判断resultHadnler等于null的情况下先从localCache里面根据key查询值,那么查询出的结果就是EXECUTION_PLACEHOLDER,此时强转为List 会报类型转换异常的错误


3.解决方案:

我在想mybaits源码作者为啥不再加一层判断,如果是从缓存取出的结果EXECUTION_PLACEHOLDER也去查询数据库,请注意:从缓存取出结果为EXECUTION_PLACEHOLDER的场景是发生在查询数据库耗时久的情况下,同一条SQL查询,如果第二个线程也去让他查,第三个也去查,那么数据库有可能在此时要是被黑客攻击利用的情况下就崩了。最好的解决方案是在从缓存取出结果为EXECUTION_PLACEHOLDER等待第一条线程取到的数据赋值给第二条线程,这里利用全局变量进行处理即可。