MyBatis源码分析-6 SecondLevelCache二级缓存及其实现原理

邢雨华
2023-12-01

                                                                                                                                                                                                                                                                  作者:田超凡

                                                                                                                                                                                                                                                                  版权所有,严禁复制转载

一级缓存 SqlSession级别的缓存 Propurtual localCache

 mybatis的一级缓存是SqlSession级别的缓存,在操作数据库的时候需要先创建SqlSession会话对象,在对象中有一个HashMap用于存储缓存数据,此HashMap是当前会话对象私有的,别的SqlSession会话对象无法访问。

 

具体流程:

1.第一次执行select完毕会将查到的数据写入SqlSession内的HashMap中缓存起来

2.第二次执行select会从缓存中查数据,如果select相同且所传参数一样,那么就能从缓存中返回数据,不用去数据库了,从而提高了效率

思考:使用什么作为一级缓存的key?

答案:CacheKey cachekey = createCacheKey()

 

 

注意事项:

1.   如果SqlSession执行了DML操作(insert、update、delete),并commit了,那么mybatis就会清空当前SqlSession缓存中的所有缓存数据,这样可以保证缓存中的存的数据永远和数据库中一致,避免出现脏读

 

 

1.   当一个SqlSession结束后那么他里面的一级缓存也就不存在了,mybatis默认是开启一级缓存,不需要配置

2.   mybatis的缓存是基于[namespace:sql语句:参数]来进行缓存的,意思就是,SqlSession的HashMap存储缓存数据时,是使用[namespace:sql:参数]作为key

 

 

注意:服务器集群的时候,每个sqlSession有自己独立的缓存相互之间不存在共享,所以在服务器集群的时候容易产生数据冲突问题。

 

配置以下配置可以实现开启日志打印

 

 

<settings>

    <setting name="logImpl" value="STDOUT_LOGGING"/>

    <setting name="cacheEnabled" value="false"/>

</settings>

 

 

 

如何禁止一级缓存

方案1  在sql语句上 随机生成 不同的参数 存在缺点:map集合可能爆 内存溢出的问题

方案2  开启二级缓存

方案3  使用sqlSession强制清除缓存

方案4  创建新的sqlSession连接。

 

 

二级缓存Mapper级别的缓存

 

二级缓存是mapper级别的缓存,也就是同一个namespace的mappe.xml,当多个SqlSession使用同一个Mapper操作数据库的时候,得到的数据会缓存在同一个二级缓存区域,二级缓存默认是没有开启的。

需要在setting全局参数中配置开启二级缓存

Config.配置

 

<settings>

    <setting name="cacheEnabled" value="true"/>

</settings>

 

在UserMapper配置

 

<!-- 以下两个<cache>标签二选一,第一个可以输出日志,第二个不输出日志 -->

<cache type="org.mybatis.caches.ehcache.LoggingEhcache" />

<!-- <cache type="org.mybatis.caches.ehcache.EhcacheCache"/> -->

 

 

二级缓存回收策略

 LRU:最近最少使用的策略,移除最长时间不被使用的对象。

 FIFO:先进先出策略,按对象进入缓存的顺序来移除它们。

 SOFT:软引用策略,移除基于垃圾回收器状态和软引用规则的对象。

 WEAK:弱引用策略,更积极地移除基于垃圾收集器状态和弱引用规则的对象。

 

 软引用与弱引用的区别:

  软引用: 软引用是用来描述一些有用但并不是必需的对象, 对于软引用关联着的对象,只有在内存不足的时候JVM才会回收该对象

  弱引用: 弱引用也是用来描述非必需对象的,当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象

  

 

 

TransactionalCache

TransactionalCache:继承自Cache接口,主要作用是保存SqlSession在事务中需要向某个二级缓存提交的缓存数据(因为事务过程中的数据可能会回滚,所以不能直接把数据就提交二级缓存,而是暂存在TransactionalCache中,在事务提交后再将过程中存放在其中的数据提交到二级缓存,如果事务回滚,则将数据清除掉)

 

 

TransactionalCacheManager

TransactionalCacheManager:用于管理CachingExecutor使用的二级缓存对象,只定义了一个transactionalCaches字段

 

private final Cache delegate;  //对应的二级缓存对象

private boolean clearOnCommit;   //是否在commit时清除二级缓存的标记

// 需要在commit时提交到二级缓存的数据

private final Map<Object, Object> entriesToAddOnCommit;

// 缓存未命中的数据,事务commit时,也会放入二级缓存(key,null)

private final Set<Object> entriesMissedInCache;

 

 

 

StatementHandler

 

StatementHandler接口的实现大致有四个,其中三个实现类都是和JDBC中的Statement响对应的:

SimpleStatementHandler,这个很简单了,就是对应我们JDBC中常用的Statement接口,用于简单SQL的处理; 存在sql注入攻击问题

PreparedStatementHandler,这个对应JDBC中的PreparedStatement,预编译SQL的接口;

防止sql注入

CallableStatementHandler,这个对应JDBC中CallableStatement,用于执行存储过程相关的接口;

RoutingStatementHandler,这个接口是以上三个接口的路由,没有实际操作,只是负责上面三个StatementHandler的创建及调用。

 

 

ResultSetHandler

就是将Statement实例执行之后返回的ResultSet结果集转换成我们需要的List结果集

 

 

一级缓存与二级缓存区别

 

①、一级缓存是SqlSession级别的缓存。在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(sqlHashMap)是互相不影响的。

②、二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。

 

注意:sqlSession缓存底层存在线程安全问题。

 类似资料: