mybatis的一级缓存和二级缓存
mybatis 的一级缓存:sqlsession 级别的,内部维护的其实就是Map,其缓存对象是PerpetualCache。
1、MyBatis的一级缓存是SqlSession级别的,但是它并不定义在SqlSessio接口的实现类DefaultSqlSession中,而是定义在DefaultSqlSession的成员变量Executor中,Executor是在openSession的时候被实例化出来的,它的默认实现为SimpleExecutor
2、MyBatis中的一级缓存,与有没有配置无关,只要SqlSession存在,MyBastis一级缓存就存在,localCache的类型是PerpetualCache,它其实很简单,一个id属性+一个HashMap属性而已,id是一个名为"localCache"的字符串,HashMap用于存储数据,Key为CacheKey,Value为查询结果
3、MyBatis的一级缓存查询的时候默认都是会先尝试从一级缓存中获取数据的,但是我们看第6行的代码做了一个判断,ms.isFlushCacheRequired(), 即想每次查询都走DB也行,将<select>标签中的flushCache属性设置为true即可,这意味着每次查询的时候都会清理一遍PerpetualCache, PerpetualCache中没数据,自然只能走DB
一级缓存失效原因:
1、是否是在同一个sqlsession连接中。
2、如果是增删改操作,程序会clear缓存。
3、手动清空缓存数据,调用sqlsession.clearCache().
4、执行语句的参数不同。缓存中也不存在数据,因为map的key是根据mapperStatment对象的id、以及sql、以及传入的参数来生成的CacheKey对象
如果mybatis整合spring
1、未开启事务,则mybatis的以及缓存 失效,每次查询都会关闭旧的sqlsession,而创建新的,因为一级缓存基于sqlsession,只要sqlsession不关闭,其缓存就一直存在,而spring是通过sqlsessionTemplaate 来管理 sqlsession,其通过代理sqlsessionProxy, 在代理对象中执行一系列的增删改查后,就会自动提交并关闭sqlsession连接。
2、在开启事物的情况之下,spring使用threadLocal获取当前资源绑定同一个sqlSession,因此此时一级缓存是有效的为使用ThreadLocal将当前线程绑定创建SqlSession相关的资源,从而获取同一个sqlSession。
二级缓存:
假如定义了MyBatis二级缓存,那么MyBatis二级缓存读取优先级高于MyBatis一级缓存。根据flushCache=true或者flushCache=false判断是否要清理二级缓存保证MyBatis二级缓存不会存储存储过程的结果尝试从tcm中获取查询结果,这个tcm解释一下,这又是一个装饰器模式(数数MyBatis用到了多少装饰器模式了),创建一个事物缓存TranactionalCache,持有Cache接口,Cache接口的实现类就是根据我们在Mapper文件中配置的<cache>创建的Cache实例
如果没有从MyBatis二级缓存中拿到数据,那么就会查一次数据库,然后放到MyBatis二级缓存中去
至于如何判定上次查询和这次查询是一次查询?由于这里的CacheKey和MyBatis一级缓存使用的是同一个CacheKey,
因此它的判定条件和前文写过的MyBatis一级缓存三个维度的判定条件是一致的。
最后再来谈一点,"Cache cache = ms.getCache()"这句代码十分重要,这意味着Cache是从MappedStatement中获取到的,
而MappedStatement又和每一个<insert>、<delete>、<update>、<select>绑定并在MyBatis启动的时候存入Configuration中:
protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection");
因此MyBatis二级缓存的生命周期即整个应用的生命周期,应用不结束,定义的二级缓存都会存在在内存中。
从这个角度考虑,为了避免MyBatis二级缓存中数据量过大导致内存溢出,MyBatis在配置文件中给我们增加了很多配置例如size(缓存大小)、
flushInterval(缓存清理时间间隔)、eviction(数据淘汰算法)来保证缓存中存储的数据不至于太过庞大。
可用的收回策略有:
【默认】LRU——最近最少使用的:移除最长时间不被使用的对象
FIFO——先进先出的:按对象进入缓存的顺序来移除他们
SOFT——软引用:移除基于垃圾回收器状态和软引用规则的对象
WEAK——弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
flushInterval(刷新间隔)可以被设置为任意的正整数(60*60*1000这种形式是不允许的),而且它们代表一个合理的毫秒形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。
size(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的可用内存资源数目。默认值是1024.
readOnly(只读)属性可以被设置为true或false。只读的缓存会给所有调用者返回缓存对象的相同实例,因此这些对象不能被修改,这提供了很重要的性能优势。可读写的缓存会返回缓存对象的拷贝(通过发序列化)。这会慢一些,但是安全,因此默认是false。
package springSourseAnalyes.sqlsessionMybatis;
import java.util.List;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.webTest.inputData.dao.GuiJiResultDateDao;
//@Service("cacheServiceImpl")
public class SqlSessionLocalCacheServiceImpl implements BeanFactoryAware{
private BeanFactory beanFactory;
// @Autowired
GuiJiResultDateDao guiJiResultMapper;
//如果再方法中调用事务方法,这时事务是失效的,,解决方法如下,
//获取事务的代理类,不然事务无效 ,.需要在配置文件中配置aop:aspectj-autoproxy 配置expose-proxy为true,或者
// 使用spring3.1.2以上版本的注解方式@EnableAspectJAutoProxy(proxyTargetClass="true",exposeProxy="true")
// ((SqlSessionLocalCacheServiceImpl)AopContext.currentProxy()).getSqlData();
public void getSqlDataTran(){
((SqlSessionLocalCacheServiceImpl)AopContext.currentProxy()).getSqlData();
// this.getSqlData();
}
@Transactional
public void getSqlData(){
// guiJiResultMapper.insertOrder(232131321);
// int i = 1/0;
List<Object> text = guiJiResultMapper.getText("1111");
List<Object> text1 = guiJiResultMapper.getText("1111");
System.out.println(text.size() + text1.size());
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
// TODO Auto-generated method stub
this.beanFactory = beanFactory;
}
}
本文详细介绍了MyBatis的一级缓存和二级缓存。一级缓存是SqlSession级别的,内部维护Map,存在失效情况,整合Spring时受事务影响。二级缓存读取优先级高于一级缓存,生命周期为整个应用周期,还介绍了其配置及可用的收回策略。

7万+

被折叠的 条评论
为什么被折叠?



