首页 > 编程知识 正文

oracle缓存机制,javaredis缓存用法

时间:2023-05-03 10:58:06 阅读:32506 作者:3630

MyBatis缓存机制详细介绍MyBatis的缓存机制。 一级缓存一级缓存调用过程一级缓存原理说明一级缓存使用注意事项二级缓存

MyBatis的缓存机制介绍

Mybatis具有非常强大的查询缓存机制,可减少系统直接和数据库数据I/o操作,大大提高查询效率。 另外,MyBatis的缓存可以简单地配置和定制。 缺省情况下,MyBatis定义两级缓存

l1缓存l1缓存是指默认情况下打开MyBatis的缓存,未为同一SqlSession设置。 如果所有查询条件都相同,则MyBatis首先直接与数据库交互,而第二个查询直接从主缓存获取数据。 以下是一级缓存的图像: 当映射器调用执行程序时,它首先检查一级缓存的范围。 默认值为SESSION。 这意味着缓存在一个会话中执行的所有查询。 也可以设置为语句。 在这种情况下,本地会话用于执行语句,同一SqlSession不会再次共享数据。

一级缓存调用过程一级缓存的本质是缓存数据的容器,但如何缓存数据? 同时,为什么一级缓存基于SqlSession级缓存? 在这里,您需要深入了解MyBatis在进行选择查询时在与数据库交互之前所做的一切。 让我们忽略前面的代码,直接进入MyBatis的运行过程。 从下面的运行栈中可以看到,随着运行过程的一步一步地推进,当MyBatis请求DefaultSqlSessio运行选择列表时,使用的执行器是CachingExecutor 我知道SqlSession执行查询的真正操作是由执行程序执行的。 所以我们直接进入CachingExecutor,去调查发生了什么。

一级缓存原理介绍了SqlSession如何将查询委托给执行程序。 此处执行程序接口的实现类是cache执行程序

dfaultsqlsession.Java @ overridepublicelisteselectlist (字符串语句,对象参数,行边界行边界) try { mmm wrapcollection(parameter ),rowBounds,Executor.NO_RESULT_HANDLER ); }catch(exceptione ) throwexceptionfactory.wrap exception (' errorqueryingdatabase.cause 3360 ' e,e ); } finally { ErrorContext.instance ().reset ); }接下来,进入CachingExecutor.class,看看执行过程。 query ) )可以看到,在提交查询之前已创建了CacheKey。 此CacheKey是使用ArrayList存储数据并创建CacheKey的工作。 已委托给MyBatisSimpleExetutor。 创建代码如下: 整个创建过程都在使用cackeKey.update (方法。 此方法创建唯一的键。 如果对执行下一个方法有用,则在调用同一方法时使用缓存执行器。 其中的key由五个规则确定: ms.getId ()、rowBounds.getOffset )、rowBounds.getLimit ()、boundSql.getSql ()和参数value

@ overridepublicelistequery (映射参数对象、原始边界原始边界、结果处理程序结果处理程序) ) 返回查询(ms,parameterObject,rowBounds,resultHandler,key,boundSql ); //创建执行器的过程@ overridepubliccachekeycreatecachekey (mappedstatementms,Object parameterObject,RowBounds rowBounds,)

losed."); } CacheKey cacheKey = new CacheKey(); cacheKey.update(ms.getId()); cacheKey.update(rowBounds.getOffset()); cacheKey.update(rowBounds.getLimit()); cacheKey.update(boundSql.getSql()); List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry(); // mimic DefaultParameterHandler logic for (ParameterMapping parameterMapping : parameterMappings) { if (parameterMapping.getMode() != ParameterMode.OUT) { Object value; String propertyName = parameterMapping.getProperty(); if (boundSql.hasAdditionalParameter(propertyName)) { value = boundSql.getAdditionalParameter(propertyName); } else if (parameterObject == null) { value = null; } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { value = parameterObject; } else { MetaObject metaObject = configuration.newMetaObject(parameterObject); value = metaObject.getValue(propertyName); } cacheKey.update(value); } } if (configuration.getEnvironment() != null) { // issue #176 cacheKey.update(configuration.getEnvironment().getId()); } return cacheKey; }

当执行顺序走到下一次的时候,我们继续跟踪发现,查询流程是先查询缓存是否存在,如果存在,继续查看是否刷新缓存,如果使用了缓存同时生成的缓存key中能查到数据,那么就获取数据,要不就委托给CacheExecutor继续执行。

@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) { 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); tcm.putObject(cache, key, list); // issue #578 and #116 } return list; } } return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); }

这里的tmc.getObject(cache,key) 中 tmc是TransactionalCacheManager 既缓存事务管理器,它的作用是对TransactionalCache进行管理,获取每个SqlSession的TransactionalCache,而TransactionalCache的作用是存储Cache,MyBatis使用的Cache有一下几种:可以看出,实现类还是非常丰富的,我们也可以自定义缓存实现类。

这一步的执行非常重要,正真的从缓存中获取数据,如果获取不到,那么久直接和数据库交互。最重要的执行方法是(List)localCache.getObject(key),这里的localCache是一级缓存容器,使用HashMap来进行数据存储。
如果缓存中获取不到数据,那么就直接在数据库中获取。 list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);,获取到之后,再执行localCache.putObject(key, list); 将数据存在缓存容器中。本质调用的是map.put()方法。
至此,我们可以看到,一级缓存的整个调用过程就完成了。最重要的执行还是以创建容器,查询数据,和数据库交互为主。这里要非常注重跟源代码,从代码中获取这个执行链进行分析。

@SuppressWarnings("unchecked") @Override 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()); if (closed) { throw new ExecutorException("Executor was closed."); } if (queryStack == 0 && ms.isFlushCacheRequired()) { clearLocalCache(); } List<E> list; try { queryStack++; list = resultHandler == null ? (List<E>) localCache.getObject(key) : null; if (list != null) { handleLocallyCachedOutputParameters(ms, key, parameter, boundSql); } else { list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql); } } finally { queryStack--; } if (queryStack == 0) { for (DeferredLoad deferredLoad : deferredLoads) { deferredLoad.load(); } // issue #601 deferredLoads.clear(); if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) { // issue #482 clearLocalCache(); } } return list; } 一级缓存使用注意事项

MyBatis在开启一个数据库会话时,会 创建一个新的SqlSession对象,SqlSession对象中会有一个新的Executor对象,Executor对象中持有一个新的PerpetualCache对象;当会话结束时,SqlSession对象及其内部的Executor对象还有PerpetualCache对象也一并释放掉。

如果SqlSession调用了close()方法,会释放掉一级缓存PerpetualCache对象,一级缓存将不可用;

如果SqlSession调用了clearCache(),会清空PerpetualCache对象中的数据,但是该对象仍可使用;

SqlSession中执行了任何一个update操作(update()、delete()、insert()) ,都会清空PerpetualCache对象的数据,但是该对象可以继续使用;

二级缓存

二级缓存是利用一级缓存的数据在SqlSession调用commit或者close时导入到二级缓存的,那么如果在利用一个SqlSession实现了更新等操作时便会刷新一级缓存从而导致在提交了事务或关闭时,一级缓存传入到二级缓存的数据是空的,如下图:当执行完executor时候,那么对数据会进行一个保存,此时如果二级缓存开着,同时SqlSession关闭或者将要提交,二级缓存就会生效。

这里就比较关键了如果没有开启二级缓存那么执行器便是默认的SimpleExecutor在这里面保存的便是一级缓存,如果开启了二级缓存,便会对执行器进行包装(CachingExecutor中便保存还未提交的二级缓存数据),这里再把Executor的图细化便是这样:

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。