mybatis的一级、二级缓存

本文详细介绍了MyBatis的一级缓存和二级缓存。一级缓存是SqlSession级别的,内部维护Map,存在失效情况,整合Spring时受事务影响。二级缓存读取优先级高于一级缓存,生命周期为整个应用周期,还介绍了其配置及可用的收回策略。

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;
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值