当前位置:首页 » 文件管理 » mybatis的缓存

mybatis的缓存

发布时间: 2022-01-08 14:46:42

1. mybatis怎么开启二级缓存

深入了解MyBatis二级缓存
一、创建Cache的完整过程
我们从sqlSessionFactoryBuilder解析mybatis-config.xml配置文件开始:
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);

然后是:
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(parser.parse());

看parser.parse()方法:
parseConfiguration(parser.evalNode("/configuration"));

看处理Mapper.xml文件的位置:
mapperElement(root.evalNode("mappers"));

看处理Mapper.xml的XMLMapperBuilder:
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration,
resource, configuration.getSqlFragments());
mapperParser.parse();

继续看parse方法:
configurationElement(parser.evalNode("/mapper"));

到这里:
String namespace = context.getStringAttribute("namespace");
if (namespace.equals("")) {
throw new BuilderException("Mapper's namespace cannot be empty");
}
builderAssistant.setCurrentNamespace(namespace);
cacheRefElement(context.evalNode("cache-ref"));
cacheElement(context.evalNode("cache"));

从这里看到namespace就是xml中<mapper>元素的属性。然后下面是先后处理的cache-ref和cache,后面的cache会覆盖前面的cache-ref,但是如果一开始cache-ref没有找到引用的cache,他就不会被覆盖,会一直到最后处理完成为止,最后如果存在cache,反而会被cache-ref覆盖。这里是不是看着有点晕、有点乱看所以千万别同时配置这两个,实际上也很少有人会这么做。
看看MyBatis如何处理<cache/>:
private void cacheElement(XNode context) throws Exception {
if (context != null) {
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);
}
}

源码可以看到MyBatis读取了那些属性,而且很容易可以到这些属性的默认值。
创建Java的cache对象方法为builderAssistant.useNewCache,我们看看这段代码:
public Cache useNewCache(Class<? extends Cache> typeClass,
Class<? extends Cache> evictionClass,
Long flushInterval,
Integer size,
boolean readWrite,
boolean blocking,
Properties props) {
typeClass = valueOrDefault(typeClass, PerpetualCache.class);
evictionClass = valueOrDefault(evictionClass, LruCache.class);
Cache cache = new CacheBuilder(currentNamespace)
.implementation(typeClass)
.addDecorator(evictionClass)
.clearInterval(flushInterval)
.size(size)
.readWrite(readWrite)
.blocking(blocking)
.properties(props)
.build();
configuration.addCache(cache);
currentCache = cache;
return cache;
}

从调用该方法的地方,我们可以看到并没有使用返回值cache,在后面的过程中创建MappedStatement的时候使用了currentCache。
二、使用Cache过程
在系统中,使用Cache的地方在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();

获取cache后,先判断是否有二级缓存。
只有通过<cache/>,<cache-ref/>或@CacheNamespace,@CacheNamespaceRef标记使用缓存的Mapper.xml或Mapper接口(同一个namespace,不能同时使用)才会有二级缓存。
if (cache != null) {

如果cache存在,那么会根据sql配置(<insert>,<select>,<update>,<delete>的flushCache属性来确定是否清空缓存。
flushCacheIfRequired(ms);

然后根据xml配置的属性useCache来判断是否使用缓存(resultHandler一般使用的默认值,很少会null)。
if (ms.isUseCache() && resultHandler == null) {

确保方法没有Out类型的参数,mybatis不支持存储过程的缓存,所以如果是存储过程,这里就会报错。
ensureNoOutParams(ms, parameterObject, boundSql);

没有问题后,就会从cache中根据key来取值:
@SuppressWarnings("unchecked")
List<E> list = (List<E>) tcm.getObject(cache, key);

如果没有缓存,就会执行查询,并且将查询结果放到缓存中。
if (list == null) {
list = delegate.<E>query(ms, parameterObject,
rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578 and #116
}

返回结果
return list;
}
}

没有缓存时,直接执行查询
return delegate.<E>query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

在上面的代码中tcm.putObject(cache, key, list);这句代码是缓存了结果。但是实际上直到sqlsession关闭,MyBatis才以序列化的形式保存到了一个Map(默认的缓存配置)中。

三、Cache使用时的注意事项
1. 只能在【只有单表操作】的表上使用缓存
不只是要保证这个表在整个系统中只有单表操作,而且和该表有关的全部操作必须全部在一个namespace下。
2. 在可以保证查询远远大于insert,update,delete操作的情况下使用缓存
这一点不需要多说,所有人都应该清楚。记住,这一点需要保证在1的前提下才可以!

四、避免使用二级缓存
可能会有很多人不理解这里,二级缓存带来的好处远远比不上他所隐藏的危害。
缓存是以namespace为单位的,不同namespace下的操作互不影响。
insert,update,delete操作会清空所在namespace下的全部缓存。
通常使用MyBatis Generator生成的代码中,都是各个表独立的,每个表都有自己的namespace。
为什么避免使用二级缓存
在符合【Cache使用时的注意事项】的要求时,并没有什么危害。
其他情况就会有很多危害了。
针对一个表的某些操作不在他独立的namespace下进行。
例如在UserMapper.xml中有大多数针对user表的操作。但是在一个XXXMapper.xml中,还有针对user单表的操作。
这会导致user在两个命名空间下的数据不一致。如果在UserMapper.xml中做了刷新缓存的操作,在XXXMapper.xml中缓存仍然有效,如果有针对user的单表查询,使用缓存的结果可能会不正确。
更危险的情况是在XXXMapper.xml做了insert,update,delete操作时,会导致UserMapper.xml中的各种操作充满未知和风险。
有关这样单表的操作可能不常见。但是你也许想到了一种常见的情况。
多表操作一定不能使用缓存
为什么不能看
首先不管多表操作写到那个namespace下,都会存在某个表不在这个namespace下的情况。
例如两个表:role和user_role,如果我想查询出某个用户的全部角色role,就一定会涉及到多表的操作。
<select id="selectUserRoles" resultType="UserRoleVO">
select * from user_role a,role b where a.roleid = b.roleid and a.userid = #{userid}
</select>123123

像上面这个查询,你会写到那个xml中呢看看
不管是写到RoleMapper.xml还是UserRoleMapper.xml,或者是一个独立的XxxMapper.xml中。如果使用了二级缓存,都会导致上面这个查询结果可能不正确。
如果你正好修改了这个用户的角色,上面这个查询使用缓存的时候结果就是错的。
这点应该很容易理解。
在我看来,就以MyBatis目前的缓存方式来看是无解的。多表操作根本不能缓存。
如果你让他们都使用同一个namespace(通过<cache-ref>)来避免脏数据,那就失去了缓存的意义。
看到这里,实际上就是说,二级缓存不能用。整篇文章介绍这么多也没什么用了。

五、挽救二级缓存看
想更高效率的使用二级缓存是解决不了了。
但是解决多表操作避免脏数据还是有法解决的。解决思路就是通过拦截器判断执行的sql涉及到那些表(可以用jsqlparser解析),然后把相关表的缓存自动清空。但是这种方式对缓存的使用效率是很低的。
设计这样一个插件是相当复杂的,既然我没想着去实现,就不废话了。
最后还是建议,放弃二级缓存,在业务层使用可控制的缓存代替更好。

2. mybatis 中的查询缓存是什么意思

一、MyBatis的Cache配置 1、全局开关:默认是true,如果它配成false,其余各个Mapper XML文件配成支持cache也没用。 <settings> <setting name="cacheEnabled" value="true"/> </settings> 2、各个Mapper XML文件,默认是不采用cache。在配置文件加一行就可以支持cache: <cache /> 3、Mapper XML文件配置支持cache后,文件中所有的Mapper statement就支持了。此时要个别对待某条,需要: <select id="inetAton" parameterType="string" resultType="integer" useCache=“false”> select inet_aton(#{name}) </select> 二、注意的几个细节 1、如果readOnly为false,此时要结果集对象是可序列化的。 <cache readOnly="false"/> 2、在SqlSession未关闭之前,如果对于同样条件进行重复查询,此时采用的是local session cache,而不是上面说的这些cache。 3、MyBatis缓存查询到的结果集对象,而非结果集数据,是将映射的PO对象集合缓存起来。 说意义不大是在于: a、面对一定规模的数据量,内置的cache方式就派不上用场了; b、对查询结果集做缓存并不是MyBatis框架擅长的,它专心做的应该是sql mapper。采用此框架的Application去构建缓存更合理,比如采用OSCache、Memcached啥的。

3. MyBatis中如何禁用缓存

默认情况下,select语句总是使用缓存,但有些情况下,我们希望它总是刷新从而得到最新数据,看了下它的文档,配置不起作用,对配置文件的

<settings>
<setting name="cacheEnabled" value="false"/>
</settings>

不起作用,对sql映射文件的
flushCache="true" useCache="false"
仍然不起作用,最后找到了彻底的办法,调用SqlSession.clearCache(),问题解决。

4. mybatis的缓存机制是怎么样的

通常为了减轻数据库的压力,我们会引入缓存。在Dao查询数据库之前,先去缓存中找是否有要找的数据,如果有则用缓存中的数据即可,就不用查询数据库了。如果没有才去数据库中查找。这样就能分担一下数据库的压力。另外,为了让缓存中的数据与数据库同步,我们应该在该数据发生变化的地方加入更新缓存的逻辑代码。这样无形之中增加了工作量,同时也是一种对原有代码的入侵。这对于有着代码洁癖的程序员来说,无疑是一种伤害。MyBatis框架早就考虑到了这些问题,因此MyBatis提供了自定义的二级缓存概念,方便引入我们自己的缓存机制,而不用更改原有的业务逻辑。

5. mybatis一级缓存实际使用场景

可以这样理解,有些时候我们会多次查询一个表,比如表A中有个字段AA1是代码,实际内容存在字典表B中,在这里如果我要查询表A中的多条数据,并且要显示AA1的实际内容,需要联查B,此时一级缓存就可以发挥作用了

6. mybatis如何设置四级缓存

两者相同点 Hibernate与MyBatis都可以是通过SessionFactoryBuider由XML配置文件生成SessionFactory,然后由SessionFactory 生成Session,最后由Session来开启执行事务和SQL语句。其中SessionFactoryBuider,SessionFactory,Session的生命周期都是差不多的。 Hibernate和MyBatis都支持JDBC和JTA事务处理。 Mybatis优势 MyBatis可以进行更为细致的SQL优化,可以减少查询字段。 MyBatis容易掌握,而Hibernate门槛较高。 Hibernate优势 Hibernate的DAO层开发比MyBatis简单,Mybatis需要维护SQL和结果映射。 Hibernate对对象的维护和缓存要比MyBatis好,对增删改查的对象的维护要方便。 Hibernate数据库移植性很好,MyBatis的数据库移植性不好,不同的数据库需要写不同SQL。 Hibernate有更好的二级缓存机制,可以使用第三方缓存。MyBatis本身提供的缓存机制不佳。

7. mybatis缓存是怎么实现的

塞上曲·蝉鸣空桑林(王昌龄)

8. MyBatis缓存

可能会有很多人不理解这里,二级缓存带来的好处远远比不上他所隐藏的危害。

  • 缓存是以namespace为单位的,不同namespace下的操作互不影响。

  • insert,update,delete操作会清空所在namespace下的全部缓存。

  • 通常使用MyBatis Generator生成的代码中,都是各个表独立的,每个表都有自己的namespace。

9. mybatis具有缓存机制,除了增删改之外

mybatis的缓存机制
mybatis的缓存分为一级缓存和二级缓存:
1 . mybatis的一级缓存是sqlsession级别的,是基于 HashMap 的本地缓存,不同的 SqlSession 之间的缓存数据区域互不影响。
MyBatis 默认开启一级缓存。
2 . mybatis的耳机缓存是mapper级别,是基于 HashMap 的本地缓存,多个 SqlSession 可以共用二级缓存,其作用域是 mapper 的同一个 namespace (基本上可以理解一个mapper容器就是一个二级缓存)。
MyBatis 默认关闭二级缓存,如果要使用二级缓存需要在SqlMapConfig.xml文件中通过
<setting name="cacheEnabled" value="true"/>
标签开启二级缓的总开关,在需要使用二级缓存的mapper文件中 通过<cache />标签,开启这个mapper的二级缓存。

10. mybatis的缓存有几种

1、一级缓存

MyBatis默认开启了一级缓存,一级缓存是在SqlSession 层面进行缓存的。即,同一个SqlSession ,多次调用同一个Mapper和同一个方法的同一个参数,只会进行一次数据库查询,然后把数据缓存到缓冲中,以后直接先从缓存中取出数据,不会直接去查数据库。

但是不同的SqlSession对象,因为不用的SqlSession都是相互隔离的,所以相同的Mapper、参数和方法,他还是会再次发送到SQL到数据库去执行,返回结果。

2、二级缓存

为了克服这个问题,需要开启二级缓存,是的缓存zaiSqlSessionFactory层面给各个SqlSession 对象共享。默认二级缓存是不开启的,需要手动进行配置。

<cache/>

如果这样配置的话,很多其他的配置就会被默认进行,如:

  • 映射文件所有的select 语句会被缓存

  • 映射文件的所有的insert、update和delete语句会刷新缓存

  • 缓存会使用默认的Least Recently Used(LRU,最近最少使用原则)的算法来回收缓存空间

  • 根据时间表,比如No Flush Interval,(CNFI,没有刷新间隔),缓存不会以任何时间顺序来刷新

  • 缓存会存储列表集合或对象(无论查询方法返回什么)的1024个引用

  • 缓存会被视为是read/write(可读/可写)的缓存,意味着对象检索不是共享的,而且可以很安全的被调用者修改,不干扰其他调用者或县城所作的潜在修改

  • 可以在开启二级缓存时候,手动配置一些属性

  • <cache eviction="LRU" flushInterval="100000" size="1024" readOnly="true"/>

  • 各个属性意义如下:

  • eviction:缓存回收策略
    - LRU:最少使用原则,移除最长时间不使用的对象
    - FIFO:先进先出原则,按照对象进入缓存顺序进行回收
    - SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象
    - WEAK:弱引用,更积极的移除移除基于垃圾回收器状态和弱引用规则的对象

  • flushInterval:刷新时间间隔,单位为毫秒,这里配置的100毫秒。如果不配置,那么只有在进行数据库修改操作才会被动刷新缓存区

  • size:引用额数目,代表缓存最多可以存储的对象个数

  • readOnly:是否只读,如果为true,则所有相同的sql语句返回的是同一个对象(有助于提高性能,但并发操作同一条数据时,可能不安全),如果设置为false,则相同的sql,后面访问的是cache的clone副本。

  • 可以在Mapper的具体方法下设置对二级缓存的访问意愿:

  • useCache配置

    如果一条语句每次都需要最新的数据,就意味着每次都需要从数据库中查询数据,可以把这个属性设置为false,如:

  • <select id="selectAll" resultMap="BaseResultMap" useCache="false">

  • 刷新缓存(就是清空缓存)

    二级缓存默认会在insert、update、delete操作后刷新缓存,可以手动配置不更新缓存,如下:

  • <update id="updateById" parameterType="User" flushCache="false" />


  • 3、自定义缓存

    自定义缓存对象,该对象必须实现 org.apache.ibatis.cache.Cache 接口

每次查询数据库前,MyBatis都会先在缓存中查找是否有该缓存对象。只有当调用了commit() 方法,MyBatis才会往缓存中写入数据,数据记录的键为数字编号+Mapper名+方法名+SQL语句+参数格式,值为返回的对象值。

热点内容
单片机android 发布:2024-09-20 09:07:24 浏览:763
如何提高三星a7安卓版本 发布:2024-09-20 08:42:35 浏览:662
如何更换服务器网站 发布:2024-09-20 08:42:34 浏览:309
子弹算法 发布:2024-09-20 08:41:55 浏览:287
手机版网易我的世界服务器推荐 发布:2024-09-20 08:41:52 浏览:815
安卓x7怎么边打游戏边看视频 发布:2024-09-20 08:41:52 浏览:160
sql数据库安全 发布:2024-09-20 08:31:32 浏览:91
苹果连接id服务器出错是怎么回事 发布:2024-09-20 08:01:07 浏览:505
编程键是什么 发布:2024-09-20 07:52:47 浏览:655
学考密码重置要求的证件是什么 发布:2024-09-20 07:19:46 浏览:479