Mybatis的缓存
mybatis是一个查询数据库的封装框架,主要是封装提供灵活的增删改sql,开发中,service层能够通过mybatis组件查询和修改数据库中表的数据;作为查询工具,mybatis有使用缓存,这里讲一下mybatis的缓存相关源码。
缓存
在计算机里面,任何信息都有源头,缓存一般指源头信息读取后,放在内存或者其他读取较快的地方,下次读取相同信息不去源头查询而是直接从内存(或者能快速存取的硬件)读取。这样可以减少硬件使用,提高读取速度。
mybatis也是这样,查询数据库的数据之后,mybatis可以把查询结果缓存到内存,下次查询如果查询语句相同,并且查询相关的表的数据没被修改过,就可以直接返回缓存中的结果,而不用去查询数据库的语句,有效节省了时间。
简单看一下mybatis一级缓存和二级缓存相关源码,学习使用
一级缓存
通过查看源码可知,一级缓存是绑定sqSsession中的,所以每次查询sqlSession不同就失效,相同的sqlSession可以使用一级缓存。
mybatis默认sqlsession:org.apache.ibatis.session.defaults.DefaultSqlSession
构造方法中传入executor(查询执行对象)
public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) { this.configuration = configuration; this.executor = executor; this.dirty = false; this.autoCommit = autoCommit; }
executor中携带一级缓存成员:
protected BaseExecutor(Configuration configuration, Transaction transaction) { this.transaction = transaction; this.deferredLoads = new ConcurrentLinkedQueue<>(); this.localCache = new PerpetualCache("LocalCache"); //默认一级缓存 this.localOutputParameterCache = new PerpetualCache("LocalOutputParameterCache"); this.closed = false; this.configuration = configuration; this.wrapper = this; }
查询使用一级缓存逻辑
org.apache.ibatis.executor.BaseExecutor.query()
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId()); List<E> list; try { queryStack++; //localCache 一级缓存 list = resultHandler == null ? (List<E>) localCache.getObject(key) : null; //先从一级缓存中获取,key是通过sql语句生成 if (list != null) { handleLocallyCachedOutputParameters(ms, key, parameter, boundSql); } else { // 如果缓存中没有 才从数据库查询 list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql); } } finally { queryStack--; } return list; } //从数据库读取数据 private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { List<E> list; localCache.putObject(key, EXECUTI<span>本文来源gaodai#ma#com搞*!代#%^码$网*</span>ON_PLACEHOLDER); try { list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql); } finally { localCache.removeObject(key);//将一级缓存清除 } localCache.putObject(key, list);//返回查询结果之前,先放入一级缓存 刷新 if (ms.getStatementType() == StatementType.CALLABLE) { localOutputParameterCache.putObject(key, parameter); } return list; }
二级缓存
二级缓存mapper中的,默认是开启的,但需要在映射文件mapper.xml中添加<cache/>标签
<mapper namespace="userMapper"> <cache/><!-- 添加cache标签表示此mapper使用二级缓存 --> </mapper>