作者:田超凡
版权所有,严禁复制转载
一级缓存 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缓存底层存在线程安全问题。