xxxx18一20岁hd第一次

MyBatis缓存你了解几许?会用吗?

发布日期:2022-06-18 17:10    点击次数:188

MyBatis缓存你了解几许?会用吗?

本文转载自微信公众号「三不山公」,作家sanbuhouzi。转载本文请接洽三不山公公众号。

MyBatis缓存你了解几许?会用吗? MyBatis缓存先容

正如大大都历久层框架一样,MyBatis 一样提供了一级缓存和二级缓存的守旧

一级缓存: 基于PerpetualCache 的 HashMap土产货缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该Session中的通盘 Cache 就将清空。 二级缓存与一级缓存其机制相通,默许亦然收受 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace),况且可自界说存储源,如 Ehcache。 关于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespaces)的进行了 C/U/D 操作后,默许该作用域下通盘 select 中的缓存将被clear。 mybatis的干系成见 SqlSession : 代表和数据库的一次会话,向用户提供了操作数据库的圭表。 MappedStatement: 代表要发往数据库推行的教唆,不错相识为是Sql的详细暗意。 Executor: 具体用来和数据库交互的推行器,给与MappedStatement动作参数。 映射接口: 在接口中会要推行的Sql用一个圭表来暗意,具体的Sql写在映射文献中。 映射文献: 不错相识为是Mybatis编写Sql的所在,通常来说每一张单表都会对应着一个映射文献,在该文献中会界说Sql语句入参和出参的体式。 一级缓存 MyBatis的一级查询缓存(也叫作土产货缓存)是基于org.apache.ibatis.cache.impl.PerpetualCache 类的 HashMap土产货缓存,其作用域是SqlSession 在归拢个SqlSession中两次推行相通的 sql 查询语句,第一次推行罢了后,会将查询限制写入到缓存中,第二次会从缓存中顺利获得数据,而不再到数据库中进行查询,这么就减少了数据库的访谒,从而升迁查询效果。 当一个 SqlSession 收尾后,该 SqlSession 中的一级查询缓存也就不存在了。 myBatis 默许一级查询缓存是开启情景,且不可关闭。 增窜改会清空缓存,不论是否commit 当SqlSession关闭和提交时,会清空一级缓存

可能你会有猜忌,我的mybatis bean是由spring 来看管的,一经屏蔽了sqlSession这个东西了?那怎样的一次操作才算是一次sqlSession呢?

spring整合mybatis后,非事务环境下,每次操作数据库都使用新的sqlSession对象。因此mybatis的一级缓存无法使用(一级缓存针对归拢个sqlsession灵验) 在开缘由物的情况之下,spring使用threadLocal获稳健前资源绑定归拢个sqlSession,因此此时一级缓存是灵验的 在开启以及缓存的时代查询得到的对象是归拢个对象。这种情况下会出现一个问题。咱们先看一下代码。
public void listMybatisModel() {         List<MybatisModel> mybatisModels = mapper.listMybatisModel();         List<MybatisModel> mybatisModelsOther = mapper.listMybatisModel();         System.out.println(mybatisModels == mybatisModelsOther);         System.out.println("list count: " + mybatisModels.size());     } 
System.out.println(mybatisModels == mybatisModelsOther); 

输出限制居然是true,这么说来是归拢个对象。会出现这种场景,第一次查出来的对象然后修改了,第二次查出来的即是修改后的对象。

一级缓存达成

对SqlSession的操作mybatis里面都是通过Executor来推行的。Executor的人命周期和SqlSession是一致的。Mybatis在Executor中创建了一级缓存,基于PerpetualCache 类的 HashMap

二级缓存 MyBatis的二级缓存是mapper界限级别的 SqlSession关闭后才会将数据写到二级缓存区域 增窜改操作,不论是否进行提交commit(),均会清空一级、二级缓存 二级缓存是默许开启的。(想开启就不必做任何确立) 二级缓存会使用 Least Recently Used (LRU,最近最少使用的)算法来收回。 笔据时辰表(如 no Flush Interval ,莫得刷新终结),缓存不会以任何时辰章程来刷新 。 缓存会存储集结或对象(不论查询圭表复返什么类型的值)的 1024 个援用。 缓存会被视为 read/write (可读/可写)的,意味着对象检索不是分享的,而且不错安全地被调用者修改,而不打扰其他调用者或线程所做的潜在修改 。

用底下这张图形容一级缓存和二级缓存的关系。

确立二级缓存

在保证二级缓存的全局确立开启的情况下,给某个xml开启二级缓存只需要在xml中添加即可

// mybatis-config.xml 中确立 <settings>     默许值为 true。即二级缓存默许是开启的     <setting name="cacheEnabled" value="true"/> </settings>  // 具体mapper.xml 中确立 <mapper namespace="cn.itcast.mybatis.mapper.UserMapper">  <!-- 开启本mapper的namespace下的二级缓存  type:指定cache接口的达成类的类型,mybatis默许使用PerpetualCache  要和ehcache整合,需要确立type为ehcache达成cache接口的类型-->   <cache />  </mapper

type:指定cache接口的达成类的类型,mybatis默许使用PerpetualCache

要和ehcache整合,需要确立type为ehcache达成cache接口的类型-->

 

淌若想要拓荒增窜改操作的时代不清空二级缓存的话,不错在其insert或delete或update中添加属性flushCache=”false”,默许为 true。

<delete id="deleteStudent" flushCache="false">     DELETE FROM user where id=#{id} </delete

 

通过以下一些确立不错修改一些缓存参数。

<cache     eviction= "FIFO"     flushlnterval="600000"     size="512"     readOnly="true" /> 

确立创建了一个FIFO缓存,并每隔 60 秒刷新一次,存储集结或对象的512个援用, 而且复返的对象被觉得是只读的,因此在不同线程中的调用者之间修改它们会导致破损。cache不错确立的属性如下。eviction (收回计谋)

LRU (最近最少使用的: 移除最永劫辰不被使用的对象,这是默许值 。FIFO (先进先出〉 :按对象参预缓存的章程来移除它们 。SOFT (软援用) :移除基于垃圾回收器情景和软援用章程的对象 。WEAK (弱援用) :更积极地移除基于垃圾收罗器情景和弱援用章程的对象

flushinterval(刷新终结)。不错被拓荒为淘气的正整数,而且它们代表一个合理 的毫秒体式的时辰段。默许情况不拓荒,即莫得刷新终结,缓存只是在调用语句时刷新。 size (援用数量)。不错被拓荒为淘气正整数,要记着缓存的对象数量和开动环境的可用内存资源数量。默许值是 1024 。 readOnly (只读)。属性不错被拓荒为 true 或 false 。只读的缓存会给通盘调用者 复返缓存对象的相通实例,因此这些对象不可被修改,这提供了很伏击的性能上风。可读写的缓存领会过序列化复返缓存对象的拷贝,这种步地会慢一些,关联词安全,因此默许是false。

当只使用注解步地确立二级缓存时,淌若在Mapper接口中,则需要加多如下确立 。

@CacheNamespace ( eviction = FifoCache.class , flushinterval = 60000 , size = 512 , readWrite = true) public interface Mapper {      } 

括号内的本色是确立缓存属性。

Mapper 接口和对应的 XML 文献是相通的定名空间,色综合色天天久久婷婷基地想使用二级缓存,两者必须同期确立(淌若接口不存在使用注解步地的圭表,不错只在 XML 中确立〉,因此按照上头的方 式进行确立就会出错 , 这个时代应该使用参照缓存。在 Mapper 接口中,参照缓存确立如下 。

@CacheNarnespaceRef(RoleMapper.class) public interface RoleMapper { 

因为想让 RoleMapper 接口中的注解圭表和 XML中的圭表使用相通的缓存,因此使用参照缓存确立RoleMapper.class,这么就会使用定名空间为xx.xxx.xxx.xxx.RoleMapper的缓存确立,即RoleMapper.xml 中确立的缓存 。Mapper 接口不错通过注解援用XML 映射文献或者其他接口的缓存,在 XML 中也不错确立参照缓存,如不错在 RoleMapper.xml 中进行如下修改 。

<cache-ref narnespace="xxx.xxx.xxx.xxx.RoleMapper"/> 

这么确立后XML 就会援用 Mapper 接口中确立的二级缓存,一样不错幸免同期确立二级缓存导致的破损。MyBatis 中很少会同期使用 Mapper 接口注解步地和XML映射文献,是以参照缓存并不是为了贬责这个问题而野心的。参照缓存除了简略通过援用其他缓存减少确立外,主要的作用是贬责脏读。

MyBatis使用SerializedCache(org.apache.ibaits.cache.decorators.SerializedCache)序列化缓存来达成可读写缓存类,井通过序列化和反序列化来保证通过缓存获得数据时,得到的是一个新的实例。因此,淌若确立为只读缓存,MyBatis就会使用Map来存储缓存值,这种情况下,从缓存中获得的对象即是归拢个实例。因为使用可读写缓存,不错使用SerializedCache序列化缓存。这个缓存类条件通盘被序列化的对象必须达成 Serializable (java.io.Serializable)接口 诚然使用序列化得到的对象都是不一样的对象修改时都是互不影响,关联词照旧不安全的。

脏读的产生

Mybatis的二级缓存是和定名空间绑定的,是以通常情况下每一个Mapper映射文献都有我方的二级缓存,不同的mapper的二级缓存互不影响。

引起脏读的操作通常发生在多表关联操作中,比如在两个不同的mapper中都触及到归拢个表的增窜改查操作,当其中一个mapper对这张表进行查询操作,此时另一个mapper进行了更新操作刷新缓存,然后第一个mapper又查询了一次,那么此次查询出的数据是脏数据。出现脏读的原因是他们的操作的缓存并不是归拢个。 脏读的幸免 mapper中的操作以单表操动作主,幸免在关联操作中使用mapper 使用参照缓存 集成EhCache缓存 缓存数据有内存和磁盘两级,不消记念容量问题。 缓存数据会在假造机重启的经由中写入磁盘。不错通过RMI、可插入API等步地进行散布式缓存。 具有缓存柔和存看管器的侦昕接口。

守旧多缓存看管器实例以及一个实例的多个缓存区域。

1. 添加神气依赖
<dependency>     <groupId>org.mybatis.caches</groupId>     <artifactId>mybatis-ehcache</artifactId>     <version>1.0.3</version> </dependency

 

2. 确立 EhCache

在 src/main/resources 目次下新增 ehcache.xml 文献。

<?xml version="1.0" encoding="UTF-8"?> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     xsi:noNamespaceSchemaLocation="ehcache.xsd"     updateCheck="false" monitoring="autodetect"     dynamicConfig="true">          <diskStore path="D:/cache" />               <defaultCache         maxElementsInMemory="3000"         eternal="false"         copyOnRead="true"   copyOnWrite="true"   timeToIdleSeconds="3600"         timeToLiveSeconds="3600"         overflowToDisk="true"         diskPersistent="true"/>  </ehcache

 

联系EhCache的戒备确立不错参考地址 http://www.ehcache.org/ehcache.xml 中的本色。

copyOnRead 的含义是,判断从缓存中读取数据时是复返对象的援用照旧复制一个对象复返。默许情况下是false,即复返数据的援用,这种情况下复返的都是相通的对象,和MyBatis默许缓存中的只读对象是相通的。淌若拓荒为 true ,那即是可读写缓存,每次读取缓存时都会复制一个新的实例 。 copyOnWrite 的含义是 ,判断写入缓存时是顺利缓存对象的援用照旧复制一个对象然后缓存,默许亦然false。淌若想使用可读写缓存,就需要将这两个属性确立为true,淌若使用只读缓存,不错不确立这两个属性,使用默许值 false 即可 。 修改Mapper.xml中的缓存确立 ehcache-cache 提供了如下 2 个可选的缓存达成。 org.mybatis.caches.ehcache.EhcacheCache org.mybatis.caches.ehcache.LoggingEhcache 这个是带日记的缓存。

在xml中添加

<cache type ="org.mybatis.caches.ehcache.EhcacheCache" /> 

只通过拓荒 type 属性就可 以使用 EhCache 缓存了,这时cache的其他属性都不会起到任何作用,针对缓存真实立都在ehcache.xml中进行。在ehcache.xml确立文献中,唯惟一个默许的缓存确立,是以确立使用EhCache缓存的Mapper映射文献都会有一个以映射文献定名空间定名的缓存。淌若想针对某一个定名空间进行确立,需要在 ehcache.xml 中添加一个和映射文献定名空间一致的缓存确立,举例针对RoleMapper不错进行如下确立。

<cache        name="tk.mybatis.simple.mapper.RoleMapper"  maxElementsInMemory="3000"        eternal="false"        copyOnRead="true"  copyOnWrite="true"  timeToIdleSeconds="3600"        timeToLiveSeconds="3600"        overflowToDisk="true"        diskPersistent="true"/> 
集成Redis缓存

添加依赖,当今唯独bata版块。

      <dependency>  <groupId>org.mybatis.caches</groupId>  <artifactId>mybatis-redis</artifactId>  <version>1.0.0-beta2</version> </dependency

 

确立Redis 使用 Redis 前,必须有一个 Redis 职业,联系Redis安设启动的干系本色,可参考如下地址中的官方文档:https://redis.io/topics/quickstart。Redis职业启动后,在src/main/resources 目次下新增 redis.properties 文献 。

host=localhost port=6379 connectionTimeout=SOOO soTimeout=SOOO password= database=O clientName= 

修改mapper.xml中真实立。

<mapper namespace = ” tk.mybat 工 s.s 工 mple.mapper.RoleMapper ” 〉 <cache type= "org.mybatis.caches.redis.RedisCache" /> 〈 !一其他我方直一 〉 </mapper

 

 

确立依然很粗浅, RedisCache 在保存缓存数据和获得缓存数据时,使用了Java的序列化和反序列化,因此还需要保证被缓存的对象必须达成Serializable接口。改为RedisCache缓存确立后, testL2Cache 测试第一次推行时会一路凯旋,关联词淌若再次推行,就会出错。这是因为Redis动作缓存职业器,它缓存的数据和关节(或测试)的启动无关,Redis 的缓存并不会因为运用的关闭而失效。是以再次推行时莫得进行一次数据库查询,通盘查询都使用缓存,测试的第一部分代码中的rolel和role2都是顺利从二级缓存中获得数据,因为是可读写缓存,是以不是相通的对象。当需要散布式部署运用时,淌若使用MyBatis自带缓存或基础的EhCahca缓存,散布式运用会各自领有我方的缓存,它们之间不会分享缓存 ,这种步地会糜费更多的职业器资源。淌若使用近似 Redis 的缓存职业,就不错将散布式运用连络到归拢个缓存职业器,达成散布式运用间的缓存分享 。

 



栏目分类



Powered by xxxx18一20岁hd第一次 @2013-2022 RSS地图 HTML地图