文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

MyBatis缓存你了解多少?会用吗?

2024-12-02 23:59

关注

MyBatis缓存你了解多少?会用吗?

MyBatis缓存介绍

正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持

  1. 一级缓存: 基于PerpetualCache 的 HashMap本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该Session中的所有 Cache 就将清空。
  2. 二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。
  3. 对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespaces)的进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。

mybatis的相关概念

  1. SqlSession : 代表和数据库的一次会话,向用户提供了操作数据库的方法。
  2. MappedStatement: 代表要发往数据库执行的指令,可以理解为是Sql的抽象表示。
  3. Executor: 具体用来和数据库交互的执行器,接受MappedStatement作为参数。
  4. 映射接口: 在接口中会要执行的Sql用一个方法来表示,具体的Sql写在映射文件中。
  5. 映射文件: 可以理解为是Mybatis编写Sql的地方,通常来说每一张单表都会对应着一个映射文件,在该文件中会定义Sql语句入参和出参的形式。

一级缓存

可能你会有疑惑,我的mybatis bean是由spring 来管理的,已经屏蔽了sqlSession这个东西了?那怎么的一次操作才算是一次sqlSession呢?

  1. public void listMybatisModel() { 
  2.         List mybatisModels = mapper.listMybatisModel(); 
  3.         List mybatisModelsOther = mapper.listMybatisModel(); 
  4.         System.out.println(mybatisModels == mybatisModelsOther); 
  5.         System.out.println("list count: " + mybatisModels.size()); 
  6.     } 
  1. System.out.println(mybatisModels == mybatisModelsOther); 

输出结果竟然是true,这样说来是同一个对象。会出现这种场景,第一次查出来的对象然后修改了,第二次查出来的就是修改后的对象。

一级缓存实现

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

二级缓存

用下面这张图描述一级缓存和二级缓存的关系。

配置二级缓存

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

  1. // mybatis-config.xml 中配置 
  2.  
  3.     默认值为 true。即二级缓存默认是开启的 
  4.     name="cacheEnabled" value="true"/> 
  5.  
  6.  
  7. // 具体mapper.xml 中配置 
  8. "cn.itcast.mybatis.mapper.UserMapper"
  9.  -- 开启本mapper的namespace下的二级缓存 
  10.  type:指定cache接口的实现类的类型,mybatis默认使用PerpetualCache 
  11.  要和ehcache整合,需要配置type为ehcache实现cache接口的类型--> 
  12.  
  13.   
  14.  
  15.  

 

如果想要设置增删改操作的时候不清空二级缓存的话,可以在其insert或delete或update中添加属性flushCache=”false”,默认为 true。

  1. <delete id="deleteStudent" flushCache="false"
  2.     DELETE FROM user where id=#{id} 
  3. delete

 

通过以下一些配置可以修改一些缓存参数。

  1.     eviction= "FIFO" 
  2.     flushlnterval="600000" 
  3.     size="512" 
  4.     readOnly="true" /> 

配置创建了一个FIFO缓存,并每隔 60 秒刷新一次,存储集合或对象的512个引用, 而且返回的对象被认为是只读的,因此在不同线程中的调用者之间修改它们会导致冲突。cache可以配置的属性如下。eviction (收回策略)

LRU (最近最少使用的: 移除最长时间不被使用的对象,这是默认值 。FIFO (先进先出〉 :按对象进入缓存的顺序来移除它们 。SOFT (软引用) :移除基于垃圾回收器状态和软引用规则的对象 。WEAK (弱引用) :更积极地移除基于垃圾收集器状态和弱引用规则的对象

当只使用注解方式配置二级缓存时,如果在Mapper接口中,则需要增加如下配置 。

  1. @CacheNamespace ( 
  2. eviction = FifoCache.class , 
  3. flushinterval = 60000 , 
  4. size = 512 , 
  5. readWrite = true
  6. public interface Mapper { 
  7.      

括号内的内容是配置缓存属性。

Mapper 接口和对应的 XML 文件是相同的命名空间,想使用二级缓存,两者必须同时配置(如果接口不存在使用注解方式的方法,可以只在 XML 中配置〉,因此按照上面的方 式进行配置就会出错 , 这个时候应该使用参照缓存。在 Mapper 接口中,参照缓存配置如下 。

  1. @CacheNarnespaceRef(RoleMapper.class) 
  2. public interface RoleMapper { 

因为想让 RoleMapper 接口中的注解方法和 XML中的方法使用相同的缓存,因此使用参照缓存配置RoleMapper.class,这样就会使用命名空间为xx.xxx.xxx.xxx.RoleMapper的缓存配置,即RoleMapper.xml 中配置的缓存 。Mapper 接口可以通过注解引用XML 映射文件或者其他接口的缓存,在 XML 中也可以配置参照缓存,如可以在 RoleMapper.xml 中进行如下修改 。

  1. "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的二级缓存互不影响。

脏读的避免

集成EhCache缓存

支持多缓存管理器实例以及一个实例的多个缓存区域。

1. 添加项目依赖

  1.  
  2.     org.mybatis.caches 
  3.     mybatis-ehcache 
  4.     1.0.3 
  5.  

 

2. 配置 EhCache

在 src/main/resources 目录下新增 ehcache.xml 文件。

  1. "1.0" encoding="UTF-8"?> 
  2. "http://www.w3.org/2001/XMLSchema-instance" 
  3.     xsi:noNamespaceSchemaLocation="ehcache.xsd" 
  4.     updateCheck="false" monitoring="autodetect" 
  5.     dynamicConfig="true"
  6.      
  7.     "D:/cache" /> 
  8.              
  9.  
  10.   maxElementsInMemory="3000"       
  11.   eternal="false"       
  12.   copyOnRead="true" 
  13.   copyOnWrite="true" 
  14.   timeToIdleSeconds="3600"       
  15.   timeToLiveSeconds="3600"       
  16.   overflowToDisk="true"       
  17.   diskPersistent="true"/>  
  18.  

 

有关EhCache的详细配置可以参考地址 http://www.ehcache.org/ehcache.xml 中的内容。

在xml中添加

  1. "org.mybatis.caches.ehcache.EhcacheCache" /> 

只通过设置 type 属性就可 以使用 EhCache 缓存了,这时cache的其他属性都不会起到任何作用,针对缓存的配置都在ehcache.xml中进行。在ehcache.xml配置文件中,只有一个默认的缓存配置,所以配置使用EhCache缓存的Mapper映射文件都会有一个以映射文件命名空间命名的缓存。如果想针对某一个命名空间进行配置,需要在 ehcache.xml 中添加一个和映射文件命名空间一致的缓存配置,例如针对RoleMapper可以进行如下配置。

  1.  name="tk.mybatis.simple.mapper.RoleMapper" 
  2.  maxElementsInMemory="3000"       
  3.  eternal="false"       
  4.  copyOnRead="true" 
  5.  copyOnWrite="true" 
  6.  timeToIdleSeconds="3600"       
  7.  timeToLiveSeconds="3600"       
  8.  overflowToDisk="true"       
  9.  diskPersistent="true"/> 

集成Redis缓存

添加依赖,目前只有bata版本。

  1.        
  2.  org.mybatis.caches 
  3.  mybatis-redis 
  4.  1.0.0-beta2 
  5.  

 

配置Redis 使用 Redis 前,必须有一个 Redis 服务,有关Redis安装启动的相关内容,可参考如下地址中的官方文档:https://redis.io/topics/quickstart。Redis服务启动后,在src/main/resources 目录下新增 redis.properties 文件 。

  1. host=localhost 
  2. port=6379 
  3. connectionTimeout=SOOO 
  4. soTimeout=SOOO 
  5. password
  6. database=O 
  7. clientName= 

修改mapper.xml中的配置。

  1. "org.mybatis.caches.redis.RedisCache" /> 
  2. 〈 !一其他自己直一 〉 
  3.  

 

 

配置依然很简单, RedisCache 在保存缓存数据和获取缓存数据时,使用了Java的序列化和反序列化,因此还需要保证被缓存的对象必须实现Serializable接口。改为RedisCache缓存配置后, testL2Cache 测试第一次执行时会全部成功,但是如果再次执行,就会出错。这是因为Redis作为缓存服务器,它缓存的数据和程序(或测试)的启动无关,Redis 的缓存并不会因为应用的关闭而失效。所以再次执行时没有进行一次数据库查询,所有查询都使用缓存,测试的第一部分代码中的rolel和role2都是直接从二级缓存中获取数据,因为是可读写缓存,所以不是相同的对象。当需要分布式部署应用时,如果使用MyBatis自带缓存或基础的EhCahca缓存,分布式应用会各自拥有自己的缓存,它们之间不会共享缓存 ,这种方式会消耗更多的服务器资源。如果使用类似 Redis 的缓存服务,就可以将分布式应用连接到同一个缓存服务器,实现分布式应用间的缓存共享 。

 

来源:三不猴子内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯