游戏电视苹果数码历史美丽
投稿投诉
美丽时装
彩妆资讯
历史明星
乐活安卓
数码常识
驾车健康
苹果问答
网络发型
电视车载
室内电影
游戏科学
音乐整形

给我五分钟,带你彻底掌握MyBatis的缓存工作原理

  前言
  在计算机的世界中,缓存无处不在,操作系统有操作系统的缓存,数据库也会有数据库的缓存,各种中间件如Redis也是用来充当缓存的作用,编程语言中又可以利用内存来作为缓存。自然的,作为一款优秀的ORM框架,MyBatis中又岂能少得了缓存,那么本文的目的就是带领大家一起探究一下MyBatis的缓存是如何实现的。给我五分钟,带你彻底掌握MyBatis的缓存工作原理为什么要缓存
  在计算机的世界中,CPU的处理速度可谓是一马当先,远远甩开了其他操作,尤其是IO操作,除了那种CPU密集型的系统,其余大部分的业务系统性能瓶颈最后或多或少都会出现在IO操作上,所以为了减少磁盘的IO次数,那么缓存是必不可少的,通过缓存的使用我们可以大大减少IO操作次数,从而在一定程度上弥补了IO操作和CPU处理速度之间的鸿沟。而在我们ORM框架中引入缓存的目的就是为了减少读取数据库的次数,从而提升查询的效率。MyBatis缓存
  MyBatis中的缓存相关类都在cache包下面,而且定义了一个顶级接口Cache,默认只有一个实现类PerpetualCache,PerpetualCache中是内部维护了一个HashMap来实现缓存。
  下图就是MyBatis中缓存相关类:
  需要注意的是decorators包下面的所有类也实现了Cache接口,那么为什么我还是要说Cache只有一个实现类呢?其实看名字就知道了,这个包里面全部是装饰器,也就是说这其实是装饰器模式的一种实现。
  我们随意打开一个装饰器:
  可以看到,最终都是调用了delegate来实现,只是将部分功能做了增强,其本身都需要依赖Cache的唯一实现类PerpetualCache(因为装饰器内需要传入Cache对象,故而只能传入PerpetualCache对象,因为接口是无法直接new出来传进去的)。
  在MyBatis中存在两种缓存,即一级缓存和二级缓存。一级缓存
  一级缓存也叫本地缓存,在MyBatis中,一级缓存是在会话(SqlSession)层面实现的,这就说明一级缓存作用范围只能在同一个SqlSession中,跨SqlSession是无效的。
  MyBatis中一级缓存是默认开启的,不需要任何配置。
  我们先来看一个例子验证一下一级缓存是不是真的存在,作用范围又是不是真的只是对同一个SqlSession有效。一级缓存真的存在吗packagecom。lonelyWolf。mybatis;importcom。lonelyWolf。mybatis。mapper。UserAddressMapper;importcom。lonelyWolf。mybatis。mapper。UserMapper;importcom。lonelyWolf。mybatis。model。LwUser;importorg。apache。ibatis。io。Resources;importorg。apache。ibatis。session。SqlSession;importorg。apache。ibatis。session。SqlSessionFactory;importorg。apache。ibatis。session。SqlSessionFactoryBuilder;importjava。io。IOException;importjava。io。InputStream;importjava。util。List;publicclassTestMyBatisCache{publicstaticvoidmain(String〔〕args)throwsIOException{Stringresourcemybatisconfig。xml;读取mybatisconfig配置文件InputStreaminputStreamResources。getResourceAsStream(resource);创建SqlSessionFactory对象SqlSessionFactorysqlSessionFactorynewSqlSessionFactoryBuilder()。build(inputStream);创建SqlSession对象SqlSessionsessionsqlSessionFactory。openSession();UserMapperuserMappersession。getMapper(UserMapper。class);ListLwUseruserListuserMapper。selectUserAndJob();ListLwUseruserList2userMapper。selectUserAndJob();}}
  执行后,输出结果如下:
  我们可以看到,sql语句只打印了一次,这就说明第2次用到了缓存,这也足以证明一级缓存确实是存在的而且默认就是是开启的。一级缓存作用范围
  现在我们再来验证一下一级缓存是否真的只对同一个SqlSession有效,我们对上面的示例代码进行如下改变:SqlSessionsession1sqlSessionFactory。openSession();SqlSessionsession2sqlSessionFactory。openSession();UserMapperuserMapper1session1。getMapper(UserMapper。class);UserMapperuserMapper2session2。getMapper(UserMapper。class);ListLwUseruserListuserMapper1。selectUserAndJob();ListLwUseruserList2userMapper2。selectUserAndJob();
  这时候再次运行,输出结果如下:
  可以看到,打印了2次,没有用到缓存,也就是不同SqlSession中不能共享一级缓存。一级缓存原理分析
  首先让我们来想一想,既然一级缓存的作用域只对同一个SqlSession有效,那么一级缓存应该存储在哪里比较合适是呢?
  是的,自然是存储在SqlSession内是最合适的,那我们来看看SqlSession的唯一实现类DefaultSqlSession:
  DefaultSqlSession中只有5个成员属性,后面3个不用说,肯定不可能用来存储缓存,然后Configuration又是一个全局的配置文件,也不合适存储一级缓存,这么看来就只有Executor比较合适了,因为我们知道,SqlSession只提供对外接口,实际执行sql的就是Executor。
  既然这样,那我们就进去看看Executor的实现类BaseExecutor:
  看到果然有一个localCache。而上面我们有提到PerpetualCache内缓存是用一个HashMap来存储缓存的,那么接下来大家肯定就有以下问题:缓存是什么时候创建的?缓存的key是怎么定义的?缓存在何时使用缓存在什么时候会失效?
  接下来就让我们逐一分析一级缓存CacheKey的构成
  既然缓存那么肯定是针对的查询语句,一级缓存的创建就是在BaseExecutor中的query方法内创建的:
  createCacheKey这个方法的代码就不贴了,在这里我总结了一下CacheKey的组成,CacheKey主要是由以下6部分组成1、将Statement中的id添加到CacheKey对象中的updateList属性2、将offset(分页偏移量)添加到CacheKey对象中的updateList属性(如果没有分页则默认0)3、将limit(每页显示的条数)添加到CacheKey对象中的updateList属性(如果没有分页则默认Integer。MAXVALUE)4、将sql语句(包括占位符?)添加到CacheKey对象中的updateList属性5、循环用户传入的参数,并将每个参数添加到CacheKey对象中的updateList属性6、如果有配置Environment,则将Environment中的id添加到CacheKey对象中的updateList属性一级缓存的使用
  创建完CacheKey之后,我们继续进入query方法:
  可以看到,在查询之前就会去localCache中根据CacheKey对象来获取缓存,获取不到才会调用后面的queryFromDatabase方法一级缓存的创建
  queryFromDatabase方法中会将查询得到的结果存储到localCache中
  一级缓存什么时候会被清除
  一级缓存的清除主要有以下两个地方:1、就是获取缓存之前会先进行判断用户是否配置了flushCachetrue属性(参考一级缓存的创建代码截图),如果配置了则会清除一级缓存。2、MyBatis全局配置属性localCacheScope配置为Statement时,那么完成一次查询就会清除缓存。3、在执行commit,rollback,update方法时会清空一级缓存。
  PS:利用插件我们也可以自己去将缓存清除,后面我们会介绍插件相关知识。二级缓存
  一级缓存因为只能在同一个SqlSession中共享,所以会存在一个问题,在分布式或者多线程的环境下,不同会话之间对于相同的数据可能会产生不同的结果,因为跨会话修改了数据是不能互相感知的,所以就有可能存在脏数据的问题,正因为一级缓存存在这种不足,所以我们需要一种作用域更大的缓存,这就是二级缓存。二级缓存的作用范围
  一级缓存作用域是SqlSession级别,所以它存储的SqlSession中的BaseExecutor之中,但是二级缓存目的就是要实现作用范围更广,那肯定是要实现跨会话共享的,在MyBatis中二级缓存的作用域是namespace,也就是作用范围是同一个命名空间,所以很显然二级缓存是需要存储在SqlSession之外的,那么二级缓存应该存储在哪里合适呢?
  在MyBatis中为了实现二级缓存,专门用了一个装饰器来维护,这就是我们上一篇文章介绍Executor时还留下的没有介绍的一个对象:CachingExecutor。如何开启二级缓存
  二级缓存相关的配置有三个地方:
  1、mybatisconfig中有一个全局配置属性,这个不配置也行,因为默认就是true。settingnamecacheEnabledvaluetrue
  想详细了解mybatisconfig的可以点击这里。
  2、在Mapper映射文件内需要配置缓存标签:cache或cacherefnamespacecom。lonelyWolf。mybatis。mapper。UserAddressMapper
  想详细了解Mapper映射的所有标签属性配置可以点击这里。
  3、在select查询语句标签上配置useCache属性,如下:selectidselectUserAndJobresultMapJobResultMap2useCachetrueselectfromlwuserselect
  以上配置第1点是默认开启的,也就是说我们只要配置第2点就可以打开二级缓存了,而第3点是当我们需要针对某一条语句来配置二级缓存时候则可以使用。
  不过开启二级缓存的时候有两点需要注意:
  1、需要commit事务之后才会生效
  2、如果使用的是默认缓存,那么结果集对象需要实现序列化接口(Serializable)
  如果不实现序列化接口则会报如下错误:
  接下来我们通过一个例子来验证一下二级缓存的存在,还是用上面一级缓存的例子进行如下改造:SqlSessionsession1sqlSessionFactory。openSession();UserMapperuserMapper1session1。getMapper(UserMapper。class);ListLwUseruserListuserMapper1。selectUserAndJob();session1。commit();注意这里需要commit,否则缓存不会生效SqlSessionsession2sqlSessionFactory。openSession();UserMapperuserMapper2session2。getMapper(UserMapper。class);ListLwUseruserList2userMapper2。selectUserAndJob();
  然后UserMapper。xml映射文件中,新增如下配置:cache
  运行代码,输出如下结果:
  上面输出结果中只输出了一次sql,说明用到了缓存,而因为我们是跨会话的,所以肯定就是二级缓存生效了。二级缓存原理分析
  上面我们提到二级缓存是通过CachingExecutor对象来实现的,那么就让我们先来看看这个对象:
  我们看到CachingExecutor中只有2个属性,第1个属性不用说了,因为CachingExecutor本身就是Executor的包装器,所以属性TransactionalCacheManager肯定就是用来管理二级缓存的,我们再进去看看TransactionalCacheManager对象是如何管理缓存的:
  TransactionalCacheManager内部非常简单,也是维护了一个HashMap来存储缓存。
  HashMap中的value是一个TransactionalCache对象,继承了Cache。
  注意上面有一个属性是临时存储二级缓存的,为什么要有这个属性,我们下面会解释。二级缓存的创建和使用
  我们在读取mybatisconfig全局配置文件的时候会根据我们配置的Executor类型来创建对应的三种Executor中的一种,然后如果我们开启了二级缓存之后,只要开启(全局配置文件中配置为true)就会使用CachingExecutor来对我们的三种基本Executor进行包装,即使Mapper。xml映射文件没有开启也会进行包装。
  接下来我们看看CachingExecutor中的query方法:
  上面方法大致经过如下流程:1、创建一级缓存的CacheKey2、获取二级缓存3、如果没有获取到二级缓存则执行被包装的Executor对象中的query方法,此时会走一级缓存中的流程。4、查询到结果之后将结果进行缓存。
  需要注意的是在事务提交之前,并不会真正存储到二级缓存,而是先存储到一个临时属性,等事务提交之后才会真正存储到二级缓存。这么做的目的就是防止脏读。因为假如你在一个事务中修改了数据,然后去查询,这时候直接缓存了,那么假如事务回滚了呢?所以这里会先临时存储一下。
  所以我们看一下commit方法:
  二级缓存如何进行包装
  最开始我们提到了一些缓存的包装类,这些都到底有什么用呢?
  在回答这个问题之前,我们先断点一下看看获取到的二级缓存长啥样:
  从上面可以看到,经过了层层包装,从内到外一次经过如下包装:1、PerpetualCache:第一层缓存,这个是缓存的唯一实现类,肯定需要。2、LruCache:二级缓存淘汰机制之一。因为我们配置的默认机制,而默认就是LRU算法淘汰机制。淘汰机制总共有4中,我们可以自己进行手动配置。3、SerializedCache:序列化缓存。这就是为什么开启了默认二级缓存我们的结果集对象需要实现序列化接口。4、LoggingCache:日志缓存。5、SynchronizedCache:同步缓存机制。这个是为了保证多线程机制下的线程安全性。
  下面就是MyBatis中所有缓存的包装汇总:
  二级缓存应该开启吗
  既然一级缓存默认是开启的,而二级缓存是需要我们手动开启的,那么我们什么时候应该开启二级缓存呢?
  1、因为所有的update操作(insert,delete,uptede)都会触发缓存的刷新,从而导致二级缓存失效,所以二级缓存适合在读多写少的场景中开启。
  2、因为二级缓存针对的是同一个namespace,所以建议是在单表操作的Mapper中使用,或者是在相关表的Mapper文件中共享同一个缓存。自定义缓存
  一级缓存可能存在脏读情况,那么二级缓存是否也可能存在呢?
  是的,默认的二级缓存毕竟也是存储在本地缓存,所以对于微服务下是可能出现脏读的情况的,所以这时候我们可能会需要自定义缓存,比如利用redis来存储缓存,而不是存储在本地内存当中。MyBatis官方提供的第三方缓存
  MyBatis官方也提供了一些第三方缓存的支持,如:encache和redis。下面我们以redis为例来演示一下:
  引入pom文件:dependencygroupIdorg。mybatis。cachesgroupIdmybatisredisartifactIdversion1。0。0beta2versiondependency
  然后缓存配置如下:cachetypeorg。mybatis。caches。redis。RedisCachecache
  然后在默认的resource路径下新建一个redis。properties文件:hostlocalhostport6379
  然后执行上面的示例,查看Cache,已经被Redis包装:
  自己实现二级缓存
  如果要实现一个自己的缓存的话,那么我们只需要新建一个类实现Cache接口就好了,然后重写其中的方法,如下:packagecom。lonelyWolf。mybatis。cache;importorg。apache。ibatis。cache。Cache;publicclassMyCacheimplementsCache{OverridepublicStringgetId(){returnnull;}OverridepublicvoidputObject(Objecto,Objecto1){}OverridepublicObjectgetObject(Objecto){returnnull;}OverridepublicObjectremoveObject(Objecto){returnnull;}Overridepublicvoidclear(){}OverridepublicintgetSize(){return0;}}
  上面自定义的缓存中,我们只需要在对应方法,如putObject方法,我们把缓存存到我们想存的地方就行了,方法全部重写之后,然后配置的时候type配上我们自己的类就可以实现了,在这里我们就不做演示了总结
  本文主要分析了MyBatis的缓存是如何实现的,并且分别演示了一级缓存和二级缓存,并分析了一级缓存和二级缓存所存在的问题,最后也介绍了如何使用第三方缓存和如何自定义我们自己的缓存,通过本文,我想大家应该可以彻底掌握MyBatis的缓存工作原理了。

重复的奥妙二年级数学教学反思《重复的奥妙》是二年级下册第七单元《数学好玩》第二课时的内容,属于综合实践活动。本节课的主要内容是引导学生通过观察、思考,体会简单的重复规律。这节课以主题情境图为载体,放手让学……小学一年级数学生活中的数教学实践与反思小学一年级数学《生活中的数》教学实践与反思主题背景让孩子们主动用数学的眼光去观察、审视现实生活,尝试从数学的角度运用所学知识和方法寻求解决实际问题的策略,从而真正成……凌辱的同义词和近义词凌辱:以强力压迫和侮辱。品学网小编为大家整理了凌辱的同义词、近义词,反义词和造句,供大家学习参考。凌辱的同义词和近义词:伤害〔注释〕使受到损害:伤害自身伤害他人伤害……语文教案树林不见了活动名称:树林不见了(认知)活动目标:1、认识火灾危险警告讯号。2、认识在旅游时烧烤地点标志。3、知道山火对大自然造成的危害。4、享受听故事的乐趣。……清清楚楚对对子清清楚楚的意思是指清晰明白有条理。清清楚楚有什么精彩的对对子呢?下面是品学网小编给大家整理的清清楚楚对对子,供大家阅读!清清楚楚对对子清清楚楚干干净净其他成语对对子……小班春天主题系列活动活动一:综合活动《绿绿的小草》活动目标:初步了解春天的特征,喜欢爱护小草。准备材料:选择合适的场地和时间重点难点:知道春天来了,小草发芽,了解其简单特征。……四年级卧薪尝胆第二课时教学设计一、教学要求:1、默读课文第四自然段,能结合课文理解卧薪尝胆的意思。2、理解课文内容,明白只有胜不骄,败不馁,才能取得胜利的道理。二、教学重点、难点:结……小学语文教学设计入学教育教材分析本课由四幅图画组成。第一幅图以欢迎新同学为主题。在校门外,老师正在迎接到校的同学。有的小同学结伴来到学校,有的小同学在家长的陪伴下来到学校。画面上,一……繁育的解释及造句繁育拼音【注音】:fanyu繁育解释【意思】:繁殖培育:优良品种。繁育造句:1、不健康:由于太多的宠物店小狗来自宠物滥育厂,他们不是被精心繁育的而……孩童之道的教学设计《孩童之道》教案教学设计一、导语:公元1913年一个晴朗的日子,印度有位诗人领着一群孩子刚从森林里玩耍归来,邮递员送给他一份电报,这是瑞典文学院发来的一个通知,告诉……初中课文山居秋暝优秀教案《山居秋暝》是王维的经典篇章,也是初中教学的重点,它通过简单的事情歌咏叙述,表达诗人内心最真实的情感,让人感到一种特别的浪漫,下面是初中课文《山居秋暝》优秀教案,一起来看看这课……五环旗教案设计课题五环旗教学设想、使学生知道的乘法口诀的来源,初步记住的乘法口诀、培养学生的竞争能力和数感。活动准备小棒、歌曲《洋娃娃和小熊跳舞》教……
论十四五政府投融资的新逻辑论十四五政府投融资的新逻辑。国庆节期间写了两篇财经文章发表于今日头条个人创作工作室,没想到获得了过万的阅读量,数百点赞,凭借流量今日头条还给予了10余元的创作奖励。今天,……长安汽车发布全新发展战略,投资1500亿,剑指300万年销量在8月24日开幕的2021长安汽车科技生态大会上,长安汽车对外发布了企业新汽车新生态发展战略,并首度亮相了阿维塔科技旗下高端智能电动车品牌的代号为E11的首款产品、长安汽车全新……热门板块风光储新能源车大全风光储海上风电(风电风能)整机商:金风科技、明阳智能、湘电股份、运达股份主轴:金雷股份、通裕重工风塔:天能重工、泰胜风能、天顺风能、大金重工叶片:……微信删除的视频还能找回来吗微信删除的视频怎么恢复微信上删除或者过期的视频一般是无法打开观看的,不过也并不是没有办法。这里有一个可以帮助大家恢复微信视频的好方法,下面一起来看看了解一下吧!微信删除的视频还能找回来吗……SurfacePro8外观配置曝光,Pro7沦为牺牲品价比百在9月22日23:00的微软发布会上,SurfacePro8和SurfaceGo3可能会一起出现。在SurfaceGo3列出详细的定价、外观和配置之后,SurfacePr……净水器真的没用吗?净水器排名前十的品牌有哪些净水器没用?你对净水器了解又有多少呢?近年水污染事件频频发生,据相关部门统计水污染事故每年都在1700起以上。全国城镇中,饮用水源地水质不安全涉及的人口达1。4亿。……AI新升级会话精灵开启文章问答服务会话精灵,作为思必驰创造的智能服务机器人,可基于启发式对话技术和复杂结构知识管理技术,帮助用户获取更清晰准确的信息,目前已作为销售助手、招聘助手、教学助手等广泛应用于会展景点、……潮流还顾家合创Z03要做年轻人的第一台电动大玩具10月18日,合创Z03正式上市,共发布4款车型,售价区间为13。28万16。88万元。随后,合创就展开了全国十城试驾会,通过场景化的场地试驾,让消费者更全面了解Z03。……2021做亚马逊晚不晚,启动资金大概几千元,可以做亚马逊吗?别做啦!你想呀做生意,启动资金只有几千块钱,几千块能干什么呀?亚马逊就是电商。侄子和外甥,他们一开始都是做的亚马逊电商,最重要两个人都是大专生。两人刚开……雅马哈竟然在YHE700A这种头戴降噪耳机上玩起了监听流上次写雅马哈耳机还是在上一次哈哈,倒也没隔多久,雅马哈YHL700A的评测是8月份发出来的,反响比较强烈。主要是那款耳机真的很能让人一眼记住,样子佩戴都很好,降噪通话不错……Web前端培训缩短Web开发时间的技巧在创建网站或web应用程序时,项目开发时间越长,交付所需的资金、时间和其他资源就越多。幸运的是,经过多年的技术进步和最佳实践的发展,开发时间可以大大缩短。本文将介绍10种易于采……口罩你用对了吗?香港消协检验30款口罩,一定要收藏口罩是重要抗疫用品2020。12。18消委会报告内地口罩平夹正细菌过滤率99。9口罩是重要抗疫用品,应严选质量较佳的口罩疫战持续,防疫质量至关重要,消委……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网