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, EXECUTION_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>
配置false可以关闭二级缓存
org.apache.ibatis.builder.xml.XMLMapperBuilder
private void configurationElement(XNode context) { try { //... cacheElement(context.evalNode("cache")); //解析cache标签 } catch (Exception e) { throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e); } } private void cacheElement(XNode context) { if (context != null) { // if hava cache tag 如果有cache标签才执行下面的逻辑 String type = context.getStringAttribute("type", "PERPETUAL"); Class<? extends Cache> typeClass = typeAliasRegistry.resolveAlias(type); String eviction = context.getStringAttribute("eviction", "LRU"); Class<? extends Cache> evictionClass = typeAliasRegistry.resolveAlias(eviction); Long flushInterval = context.getLongAttribute("flushInterval"); Integer size = context.getIntAttribute("size"); boolean readWrite = !context.getBooleanAttribute("readOnly", false); boolean blocking = context.getBooleanAttribute("blocking", false); Properties props = context.getChildrenAsProperties(); builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, blocking, props);//建立二级缓存 } }
org.apache.ibatis.builder.MapperBuilderAssistant.useNewCache():
public Cache useNewCache(Class<? extends Cache> typeClass, Class<? extends Cache> evictionClass, Long flushInterval, Integer size, boolean readWrite, boolean blocking, Properties props) { Cache cache = new CacheBuilder(currentNamespace) .implementation(valueOrDefault(typeClass, PerpetualCache.class)) .addDecorator(valueOrDefault(evictionClass, LruCache.class)) .clearInterval(flushInterval) .size(size) .readWrite(readWrite) .blocking(blocking) .properties(props) .build(); configuration.addCache(cache);//二级缓存赋值,如果cache标签为空,不会执行此方法,currentCache为空 currentCache = cache; return cache; }
在映射文件mapper中如果没有cache标签,不会执行上面的useNewCache方法,cache为null,就不会使用二级缓存(相当于失效)。
org.apache.ibatis.executor.CachingExecutor :
@Override public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { Cache cache = ms.getCache(); if (cache != null) {//如果二级缓存对象不为空 尝试在二级缓存中获取(没有cache标签此对象就是空) flushCacheIfRequired(ms); if (ms.isUseCache() && resultHandler == null) { ensureNoOutParams(ms, boundSql); @SuppressWarnings("unchecked") List<E> list = (List<E>) tcm.getObject(cache, key); //从二级缓存中获取数据 if (list == null) { list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); //如果为空,使用delegate查询(BaseExecutor) tcm.putObject(cache, key, list); // 查询结果保存到二级缓存 } return list; } } return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); }
二级缓存和一级缓存不用想,数据库的数据被修改是要清空缓存的,不然数据有误,至于怎么清空,是另一套逻辑了,mapper中的cache标签可以配置一些参数,比如缓存定期清空。
mybatis默认是先查询二级缓存,没有,再查看一级缓存,都为空,最后查询数据库
以上就是详解Mybatis的缓存的详细内容,更多关于Mybatis的缓存的资料请关注小牛知识库其它相关文章!
本文向大家介绍详解Mybatis的二级缓存配置,包括了详解Mybatis的二级缓存配置的使用技巧和注意事项,需要的朋友参考一下 一个项目中肯定会存在很多共用的查询数据,对于这一部分的数据,没必要 每一个用户访问时都去查询数据库,因此配置二级缓存将是非常必要的。 Mybatis的二级缓存配置相当容易,要开启二级缓存,只需要在你的Mapper 映射文件中添加一行: <cache /> 它将采用默认的行
本文向大家介绍详解Java的MyBatis框架中的缓存与缓存的使用改进,包括了详解Java的MyBatis框架中的缓存与缓存的使用改进的使用技巧和注意事项,需要的朋友参考一下 一级缓存与二级缓存 MyBatis将数据缓存设计成两级结构,分为一级缓存、二级缓存: 一级缓存是Session会话级别的缓存,位于表示一次数据库会话的SqlSession对象之中,又被称之为本地缓存。一级缓存是MyBatis
本文向大家介绍Mybatis-Plus和Mybatis的区别详解,包括了Mybatis-Plus和Mybatis的区别详解的使用技巧和注意事项,需要的朋友参考一下 原文:https://blog.csdn.net/qq_34508530/article/details/88943858 . 区别一 如果Mybatis Plus是扳手,那Mybatis Generator就是生产扳手的工厂。 通俗来
本文向大家介绍mybatis中的缓存问题解析,包括了mybatis中的缓存问题解析的使用技巧和注意事项,需要的朋友参考一下 关于mybatis基础我们前面几篇博客已经介绍了很多了,今天我们来说一个简单的问题,那就是mybatis中的缓存问题。mybatis本身对缓存提供了支持,但是如果我们没有进行任何配置,那么默认情况下系统只开启了一级缓存,一级缓存就是同一个SqlSession执行的相同查询是会
主要内容:一级缓存,二级缓存缓存可以将数据保存在内存中,是互联网系统常常用到的。目前流行的缓存服务器有 MongoDB、Redis、Ehcache 等。缓存是在计算机内存上保存的数据,读取时无需再从磁盘读入,因此具备快速读取和使用的特点。 和大多数持久化框架一样,MyBatis 提供了一级缓存和二级缓存的支持。默认情况下,MyBatis 只开启一级缓存。 一级缓存 一级缓存是基于 PerpetualCache(MyBatis
1. 前言 频繁地查询必然会给数据库带来巨大的压力,为此 MyBatis 提供了丰富的缓存功能。缓存可以有效的提升查询效率、缓解数据库压力,提高应用的稳健性。 MyBatis 的缓存有两层,默认情况下会开启一级缓存,并提供了开启二级缓存的配置。本小节我们将一起学习 MyBatis 的缓存,充分地了解和使用它。 2. 一级缓存 MyBatis 一级缓存是默认开启的,缓存的有效范围是一个会话内。一个会