尚硅谷-MyBatis3.5.7-非零基础-笔记篇-03

面试最爱问这些,缓存的作用和机制啦,特别是MyBatis还有跟Redis结合的部分!潸然泪下!希望多年以后,我看到我写的这些笔记,能很“不屑”地说一句,“诶呀,不过就是balabala”哈哈哈

MyBatis的缓存机制 

MyBatis的一级缓存

一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问。

使一级缓存失效的四种情况:
1) 不同的 SqlSession 对应不同的一级缓存
2) 同一个 SqlSession 但是查询条件不同
3) 同一个 SqlSession 两次查询期间执行了任何一次增删改操作
4) 同一个 SqlSession 两次查询期间手动清空了缓存

 一级缓存也称为本地缓存,第一篇笔记debug的时候,如果有印象,应该见过localCache这个变量,当MyBatis设置完参数和参数值映射关系,准备执行SQL时,当查询二级缓存和一级缓存都没有命中时,就会直接从数据库查询了,查询返回的结果,会先放到一级缓存中,然后再返回。

localCache.putObject(key, EXECUTION_PLACEHOLDER) 先在缓存中占个位置

try查询返回结果list前,先执行finally,把这个占的位置拿出来removeObject

localCache.putObject(key, list),正式把查询结果放到本地缓存中

key就是hashCode + 查询的sql id + sql语句 + 参数

 当sqlSession flush或close后,sqlSession中的localCache就会被清空。

本地缓存不能被关闭,但可以调用clearCache()清空本地缓存,或改变缓存的作用域(比如二级缓存若开启的话,一级缓存的东西就会放到二级缓存了)我还以为是这个意思呢

mybatis3.1之后可以配置本地缓存的作用域:mybatis.xml

MyBatis利用本地缓存机制(Local Cache)防止循环引用(循环引用)和加速重复嵌套查询。

属性localCacheScope,可选项SESSION | STATEMENT,默认是SESSION,会缓存一个sqlSession中执行的所有查询,但如果是STATEMENT,官方的说法是本地会话仅在语句执行上,对同一个sqlSession的不同调用,将不会共享数据。

总的来说:在update、insert、delete、flushCache=“true”、commit、rollback、LocalCacheScope.STATEMENT等情况下,一级缓存就都会被清空。

演示一级缓存的功力~~~

相同sqlSession、相同mapper对象或者不同mapper对象都会使用一级缓存:

演示一级缓存失效的几种情况

1) 不同的SqlSession对应不同的一级缓存

2) 同一个SqlSession但是查询条件不同

3) 同一个SqlSession两次查询期间执行了任何一次增删改操作

注意!!!这里增删改不一定是这个mapper,任意mapper有增删改都会使本地缓存刷新掉。 

4) 同一个SqlSession两次查询期间手动清空了缓存

MyBatis的二级缓存

二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取。

在尚硅谷2018年发布的教程课件中,也有说法二级缓存是namespace级别的,也就是Mapper级别的,这个看怎么理解,二级缓存和一级缓存其实是有交叉的,并不是包含的关系,但namespace一致的情况下,二级缓存包含了所有sqlSession的本地缓存,这么理解,是不是就是sqlSessionFactory级别的?

为了更好地扩展功能,也可以通过实现cache接口自定义二级缓存。

二级缓存开启的条件:
a> 在核心配置文件中,设置全局配置属性 cacheEnabled="true" ,默认为 true ,不需要设置
b> 在映射文件中设置标签 <cache />

二级缓存(second level cache),全局作用域缓存,默认不开启,需手动配置

二级缓存只有在sqlSession关闭或提交之后才会生效

 演示一下二级缓存的功力~~~

<!--设置全局配置属性cacheEnabled="true",默认为true,不需要设置-->
<settings>
    <setting name="cacheEnabled" value="true"/>
</settings>

在映射文件中设置标签<cache/>或<cache></cache> 

 

于是不出意外的话,就出意外了;感受到了二级缓存,但命中率怎么都是0!!! 

原因就在获取sqlSession的这个工具类!!!这个时候,就可以理解上面说的二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存。而这里工具类中,每次调用sqlSession,sqlSessionFactory都是全新的,上面两个SQL根本就是在两个sqlSessionFactory中,也就是涉及两个二级缓存。

public class SqlSessionUtil {
    public static SqlSession getSqlSession() {
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        return sqlSession;
    }
}

 因此,我们不能再使用这个工具类去获取sqlSession了。

这里可以看到Cache Hit Ratio [com.coffeeship.mapper.UserMapper]: 0.5,命中了

这里为什么是0.5呢,因为第一次查询算一次,第二次本身是一次,这样就是0.5,再查一次,命中率就是2/3了。

然后为什么这里返回两个对象是false呢,那是因为二级缓存的配置中,我使用的都是默认的配置,比方说readOnly,默认是false,会返回缓存对象的拷贝。

这里我们可以试着更改一下二级缓存配置:

<cache readOnly="true"></cache>

 这里返回的就是缓存对象的相同实例,因此两个对象就是一样的。

使二级缓存失效的情况:
两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效

 这里千万注意!!!又感觉2018那个教程说的二级缓存是namespace级别的,是对的了。这里我尝试在EmpMapper名称空间进行增加数据操作,发现UserMapper那还是用到了二级缓存。

 但UserMapper名称空间发生增加数据操作后,虽然命中率

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值