专栏电商日志财经减肥爱情
投稿投诉
爱情常识
搭配分娩
减肥两性
孕期塑形
财经教案
论文美文
日志体育
养生学堂
电商科学
头戴业界
专栏星座
用品音乐

Mybatis的一二级缓存原理解析(请使用mybatis跟着

  SqlSessionFactory
  SqlSessionFactory:主要作用是创建SqlSession。SqlSessionFactory的生命周期随着整个Mybatis框架的运行而运行,随着Mybatis框架的销毁而销毁。SqlSession
  SqlSession:主要是用来执行sql。
  一级缓存
  mybatis是默认开启一级缓存的。而一级缓存的作用域是SqlSession。接下来使用mybatis的查询来验证一下一级缓存。
  整体代码:加载mybatis配置文件
  Stringsourcemybatismybatisconfig。xml;
  InputStreaminputStreamResources。getResourceAsStream(source);
  创建SqlSessionFactory工厂对象
  SqlSessionFactoryfactorynewSqlSessionFactoryBuilder()。build(inputStream);
  利用工厂对象创建session会话
  SqlSessionsession1factory。openSession();
  SqlSessionsession2factory。openSession();
  第一个mapper
  LocalMapperlocalMappersession1。getMapper(LocalMapper。class);
  TbLocallocallocalMapper。cc();查询出来的对象
  session1。commit();
  第二个mapper
  LocalMapperlocalMapper1session2。getMapper(LocalMapper。class);
  TbLocaltbLocallocalMapper1。cc();查询出来的对象查询逻辑分析(query)Override
  publicListquery(MappedStatementms,ObjectparameterObject,RowBoundsrowBounds,ResultHandlerresultHandler,CacheKeykey,BoundSqlboundSql)
  throwsSQLException{
  获取二级缓存
  Cachecachems。getCache();
  判断二级缓存是否为空(为空就进入一级缓存。不为空就进入二级缓存)
  if(cache!null){
  flushCacheIfRequired(ms);
  if(ms。isUseCache()resultHandlernull){
  ensureNoOutParams(ms,boundSql);
  SuppressWarnings(unchecked)
  Listlist(List)tcm。getObject(cache,key);
  if(listnull){
  listdelegate。query(ms,parameterObject,rowBounds,resultHandler,key,boundSql);
  tcm。putObject(cache,key,list);issue578and116
  }
  returnlist;
  }
  }
  具体执行一级缓存的逻辑
  returndelegate。query(ms,parameterObject,rowBounds,resultHandler,key,boundSql);
  }blockquote
  2。往一级缓存中(query()方法)中走Override
  publicListquery(MappedStatementms,Objectparameter,RowBoundsrowBounds,ResultHandlerresultHandler,CacheKeykey,BoundSqlboundSql)throwsSQLException{
  ErrorContext。instance()。resource(ms。getResource())。activity(executingaquery)。object(ms。getId());
  if(closed){
  thrownewExecutorException(Executorwasclosed。);
  }
  if(queryStack0ms。isFlushCacheRequired()){
  clearLocalCache();
  }
  Listlist;
  try{
  queryStack;
  从一级缓存中获取
  listresultHandlernull?(List)localCache。getObject(key):null;
  if(list!null){
  如果不为空,执行的操作。然后直接返回list
  handleLocallyCachedOutputParameters(ms,key,parameter,boundSql);
  }else{
  如果为空,去数据库中查询获取
  listqueryFromDatabase(ms,parameter,rowBounds,resultHandler,key,boundSql);
  }
  }finally{
  queryStack;
  }
  if(queryStack0){
  for(DeferredLoaddeferredLoad:deferredLoads){
  deferredLoad。load();
  }
  issue601
  deferredLoads。clear();
  if(configuration。getLocalCacheScope()LocalCacheScope。STATEMENT){
  issue482
  clearLocalCache();
  }
  }
  returnlist;
  }blockquote
  咱们仔细看这一段代码。从一级缓存中获取对象
  listresultHandlernull?(List)localCache。getObject(key):null;
  进入localCache。getObject()方法中。
  我们看到localCache的类型是PerpetualCache,其中cache为一个map,暂时猜测一级缓存就在这个map中。那么可以得出,在sqlsession查询时,会将缓存put到PerpetualCache中的cache中。
  而我们知道,一级缓存作用域是SqlSeesion,那我就可以猜测PerpetualCache对象应该是在创建SqlSeesion时创建的。
  接下来进入openSession的源码分析(也就是创建SqlSession的执行逻辑),看看有没有创建PerpetualCache创建SqlSessionFactory工厂对象
  SqlSessionFactoryfactorynewSqlSessionFactoryBuilder()。build(inputStream);
  利用工厂对象创建session会话
  SqlSessionsession1factory。openSession();
  3。openSession的执行过程分析
  进入openSession一路调试进入到如下方法中,并且进入newExecutor方法中(前面的一些配置信息,暂时忽略,咱们只看和缓存相关即可)。
  再进入newExecutor方法中。
  在该方法中创建了一些和Executor相关的对象。调试后发现只能进入,newSimpleExcutor和newCachingExecutor中(下图)。咱们先看SimpleExcutor。咱们根据下图片右边圈出来的类继承关系图,就能知道。不管创建哪个Excutor对象,肯定会先创建父类的BaseExecutor对象。
  咱再看看顶层的BaseExecutor都有哪些属性。
  从这里可以看出,BaseExecutor中包含了PerpetualCache。也就是上文所解释的一级缓存主要的存储对象。
  我们再看看newCachingExecutor(executor);对象。我们可以看到,CachingExecutor中将delegate设置了值,而delegate是Excutor类型。BaseExecutor继承Excutor。所以delegate属性中有BaseExecutor对象(也就是一级缓存)。
  那么由此得出,在创建sqlsession时,会先创建PerpetualCache对象,在进行查询时,会将缓存put入PerpetualCache的cacha中。那么也就可以解释为什么一级缓存的作用域是sqlSeesion了。每个SqlSeesion的创建都会创建一个PerpetualCache,一个sqlsession对应一个PerpetualCache。二级缓存
  二级缓存作用域是SqlSessionFactory。随着SqlSessionFactory创建而创建,销毁而销毁。继续进入查询方法如下。也就是上文中的查询(query)方法:获取二级缓存
  Cachecachems。getCache();
  if(cache!null){
  二级缓存不为空
  flushCacheIfRequired(ms);
  if(ms。isUseCache()resultHandlernull){
  ensureNoOutParams(ms,boundSql);
  SuppressWarnings(unchecked)
  从tcm中获取(该tcm实际上并不是二级缓存,而是暂存区(后续commit方法中会讲解)。咱们接下来进入tcm中查看)
  Listlist(List)tcm。getObject(cache,key);
  if(listnull){
  listdelegate。query(ms,parameterObject,rowBounds,resultHandler,key,boundSql);
  tcm。putObject(cache,key,list);issue578and116
  }
  returnlist;
  }
  }blockquote
  进入tcm。getObject()方法中
  发现tcm是一个TransactionalCacheManager类型的对象。其中有个属性transactionalCaches(value值),key为Cache,value为TransactionalCache。tcm。getObject方法中的getTransactionalCache方法实际上就是创建了一个TransactionalCache对象,然后再调用TransactionalCache类中的getObject方法,那么进入TransactionalCache中的getObject方法中。如下:
  1。Objectobjectdelegate。getObject(key);
  delegate可以看到类型为Cache。使用过mybatis二级缓存的都知道。我们可以自己实现一个Cache接口,去实现自定义缓存。而这里的getObject方法就可以进入到我们自定义二级缓存中的实现中去。这里的意思是从二级缓存中获取数据。第一次查询肯定为空。
  2。entriesMissedInCache。add(key);
  如果为空则将key添加到entriesMissedInCache中,key为namespacesql一些序列化的东西。标识唯一。然后返回,回到query方法
  我们再进入到query方法中:
  代码解释如下:
  Listlist(List)tcm。getObject(cache,key);
  if(listnull){
  如果二级缓存不存在该数据,则从数据库中查询
  listdelegate。query(ms,parameterObject,rowBounds,resultHandler,key,boundSql);
  再将查询到的数据添加到暂存区中
  这里主要是添加到TransactionalCacheManager对象(暂存区)中的map中去
  tcm。putObject(cache,key,list);issue578and116
  }blockquote
  由此我们总结出,mybatis的二级缓存在查询时,并不会立刻将数据存入Chache(二级缓存)中。那我们可以思考一下,在什么时候才能将数据存入Cache(二级缓存)中呢。为了解决疑惑,咱们继续进入commit()方法中查看。commit执行分析
  这里主要两步操作。
  1。delegate。commit清空一级缓存(这里为什么要清空一级缓存呢?)
  首先我们知道,一级缓存作用域是sqlsession。在同一个事务的情况下,mybatis执行的所有sql都是同一个sqlsession对象进行操作的。除非创建了一个新的事务。spring中使用Transactional(propagationPropagation。REQUIRESNEW)来创建一个新的事务。那么此时,在新事务中会new一个sqlsession来执行sql。那么如果我们在同一个事务中,执行多条sql时都是同一个sqlsession。只有当sql执行完了之后,并且无异常,commit后,就将一级缓存清除。注意:如果在执行sql出现异常并调用session。rollback时,也会清除缓存。
  进入delegate。commit方法中,最终会进入如下方法:Override
  publicvoidclearLocalCache(){
  if(!closed){
  这里的localCache就是一级缓存(PerpetualCache对象)
  localCache。clear();
  localOutputParameterCache。clear();
  }
  }
  2。tcm。commit清除二级缓存。
  进入tcm。commit中publicvoidcommit(){
  遍历暂存区中的数据
  for(TransactionalCachetxCache:transactionalCaches。values()){
  txCache。commit();
  }
  }
  进入txCache。commit();publicvoidcommit(){
  clearOnCommit:true表示执行了更新,修改,添加操作。false表示执行了查询操作。
  if(clearOnCommit){
  如果没有执行查询操作,则将二级缓存清空(这里如果实现列自定义的二级缓存,会进入自定义实现类中)
  delegate:的类型是Cache(二级缓存)。
  delegate。clear();
  }
  将暂存区的数据添加到二级缓存中。
  flushPendingEntries();
  reset();
  }
  进入flushPendingEntries();privatevoidflushPendingEntries(){
  遍历拿到暂存区中的数据,一个一个添加到二级缓存中
  for(Map。EntryObject,Objectentry:entriesToAddOnCommit。entrySet()){
  delegate。putObject(entry。getKey(),entry。getValue());
  }
  for(Objectentry:entriesMissedInCache){
  if(!entriesToAddOnCommit。containsKey(entry)){
  delegate。putObject(entry,null);
  }
  }
  }
  那么flushPendingEntries方法具体执行逻辑为:遍历所有的暂存区的数据,添加到缓存中。
  因此证实了我的猜想,二级缓存逻辑。查询会将数据存入暂存区中,只有等到sql执行完成并没有异常。commit之后。才会将数据存入二级缓存中。并且commit时还会判断是不是修改操作。如果是的话,会清空二级缓存。那么我们继续看修改操作。修改执行过程
  修改源码跟踪
  进入flushCacheIfRequired(ms);如下:privatevoidflushCacheIfRequired(MappedStatementms){
  获取二级缓存中的数据。
  Cachecachems。getCache();
  if(cache!nullms。isFlushCacheRequired()){
  如果二级缓存不为空,清空暂存区的数据
  tcm。clear(cache);
  }
  }
  进入tcm。clear(cache);如下:
  这里看到,是进入了暂存区中的clear方法。因此这里执行的是清空暂存区的数据。咱们继续往下看。Override
  publicvoidclear(){
  这个属性是之前commit中的那个判断。修改就设置为true
  clearOnCommittrue;
  清空暂存区的数据
  entriesToAddOnCommit。clear();
  }
  回到上面我说的修改源码开头。如下
  进入update方法:
  然后直接进入clearLocalCache方法。如下:Override
  publicvoidclearLocalCache(){
  if(!closed){
  这里的localCache是PerpetualCache对象。
  localCache。clear();
  localOutputParameterCache。clear();
  }
  }
  在文章开头源码的解释已经了解到。PerpetualCache是一级缓存对象。因此这里主要的逻辑是清空一级缓存。
  最后让我们继续回顾一下修改的方法:
  flushCacheIfRequired:主要的功能是清空二级缓存
  delegate。update(ms,parameterObject):主要的逻辑是清空一级缓存。
  因此我们结合之前查询,commit,修改来说:不管是查询还是修改,在二级缓存情况下。
  查询:只会将数据存入暂存区。
  修改:只会将暂存区的数据清除。
  commit:
  1。判断是否是修改操作。修改就清空二级缓存
  2。不是修改。就遍历暂存区的数据,然后一个一个添加到二级缓存中。flushPendingEntries方法在上面的commit中。

逆水寒网易魔兽老兵服将于1月13日正式开启日前,网易逆水寒官方发布了一则给逆水寒及魔兽玩家的一封长信,宣布将在暴雪游戏服务器关闭后为玩家提供一组网易魔兽老兵主题服务器。今日,官方再度通报称,经过与大量玩家的访谈和商讨,结合3秒生成行程卡纪念版疯传!多个相关服务被暂停,这方面要当心!这样的小程序是否合规?2022年12月13日0时通信行程卡正式下线一些有仪式感的网友赶在零点前截了个图,留作纪念与此同时一项名为行程卡纪念版的新型服务也随即在朋友圈流行其依托微信小不入耳式耳机怎么样,盘点五款不错的不入耳式耳机分享随着新型骨传导耳机的诞生,凭借着听歌不入耳,健康的传声方式受到了许多用户的拥戴,瞬间在耳机圈火热起来,但在市面上骨传导耳机的类型众生繁衍,在选择的时候难免会有困惑,一时间不知道哪款如何识别手写文字?手写文字识别一键搞定想要快捷又准确地识别出手写文字,有什么办法可以搞定?对于图片文字的识别工作非常常见,但是一般的图片文字都是打印字体,识别起来比较简单,但对于手写的文字,想要识别就有点难度了,本期就马云在做什么?网络上有种观点,马云在全世界跑,是在布局新的商业,让阿里巴巴走向国际化,但这种猜测还处于猜测阶段,因为看到不到实质性举动,他是不是在退休享福,谁也说不清楚。据说在日本待了半年,当初全新宝马M2上市,现在还买燃油高性能车是不是人傻钱多?现在还有人会花五六十万元去买一个燃油高性能车吗?我觉得这样的人有,但肯定不是很多了。因为现在市面上五六十万元的新能源汽车,在性能上,操控性上其实已经非常好了,一点儿都不输给燃油高性中女感,会是新一轮的流行密码吗?中女这个词,网络上指的是有经济基础的大龄单身女性。比如剧中杨幂饰演的秦施,顶尖律所的34岁金牌律师,双商在线,经济独立,思想成熟。除了有颜有钱,品味也是极好。看她的白领look堪比我的自白我走在幻境中,每天都在想着出去的路,我一直有一个坚定的信仰我一定能走出来,我每天不断摸索寻找阵眼,终于我找到了,我感到非常自豪,我仿佛看到了一条康庄大道,不再迷茫,当我走到出口的时红旗渠游玩攻略大家好!我请大家看一组官网数据红旗渠工程于1960年2月动工,至1969年7月支渠配套工程全面完成,历时近十年。该工程共削平了1250座山头,架设151座渡槽,开凿211个隧洞,修2023年1月起,电动车迎来消息,上路门槛提高,望车主提前了解随着天气逐渐变冷,我们的出行方式出现了变化,道路上的非机动车数量不断变少,取而代之的是越来越多的私家车。国内私家车的数量也已经超过了三亿,尤其是在新能源汽车出现之后,几乎每个月的销防封号的外呼系统,电话防封系统现今,大多企业为了防封的同时也为了提高工作效率减少员工工作量,从而会使用这么一款防封系统。通过这套系统的使用,可以有效降低高频外呼的封号,从而减少封号的几率!智创良品外呼防封系统软
黑曜石新作Pentiment11月15日发售首发加入XGP今日(8月23日),微软官方宣布黑曜石叙事RPG新作Pentiment将于11月15日正式发售,登陆XSXSXboxone和PC平台,该作首发加入XGP及PGP,据此前报道消息,P科隆国际游戏展开幕夜,米哈游,网易等多个厂家亮相科隆游戏展也是众多玩家关注的一个蛮重要的游戏展会了,历经了两次疫情的拉胯,这次科隆游戏展带来的内容不可谓不丰富,不多说了,进入正题。燕云十六声虽然宣传片上有着对马岛的既视感,但我特吃饭时,第一筷子吃什么,决定你活多久!最后一口吃不对,多生6种病!别以为是小事大家有留意过,自己每顿饭的第一口和最后一口,都吃些啥?是米饭蔬菜,还是肉类汤品?我们平时养生,大多会把注意力放在吃什么吃多少上面,往往忽视第一口和最后一口吃什么。有人说,先菜后饭,糖尿病人特别饿的时候要怎么吃?糖尿病患者产生饥饿感,一般情况下有两大常见原因。一是饮食控制过分严格。部分糖尿病患者的三餐摄入量偏少,能量摄入不足,从而产生饥饿感。因此,可以在两餐之间增加零食作为补充,这种方法对无糖饮料为何会比有糖饮料危害更大1长期饮用无糖饮料对人体有什么危害?相比无味的白开水,我们更喜欢调味饮料,尤其是甜苏打水。但现在人们越来越注重养生,觉得喝太多加糖饮料对人体有害。所以现在市场上有很多无糖饮料。现在贴秋膘是有讲究的!这三类人不宜贸然进补入秋之后,气温逐渐降低,凉爽的气候让人胃口大开。正赶上贴秋膘的好时候,那么,我们现在可以大吃大喝了吗?快停下吧,因为贴秋膘是有讲究的!贴秋膘前,先理脾胃由于夏季人们贪凉食冷,大多有寿命长的人,一般有这5大共同点,若占一个,你也是幸运儿长寿应该是每个人一生的追求。然而,长寿并不那么容易。事实上,在我们的日常生活中,很多因素决定了我们寿命的长短,比如个人健康状况家族遗传生活环境等。如何在日常生活中实现真正的长寿?寿养生保健开启换季模式,专家支招秋季如何养肺交汇点讯俗话说春养肝,夏养心,秋养肺,冬养肾。夏末秋初,正是天气由热转凉的阶段,早晚温差较大,秋天气候干燥,人体呼吸系统容易受到侵犯,这时最要注意养肺。本期节气话养生记者邀请江苏省在家就可以训练的专注力游戏,我们替大家准备好了在家就可以操作的上百个不同的趣味专注力小游戏,每天30分钟高质量亲子陪伴,天天游戏不重复,孩子训练不枯燥,持之以恒从视觉听觉手眼协调等各个方面提高孩子专注力!幼儿版针对年龄36岁入世界上有成千上万种毒药,哪一种比人心更毒?说起中国式的恐怖游戏,和主流的恐怖不一样,就是让人吃惊,让人震撼。反而是中国的传统文化和封建不良风气给了玩家一种无比恐惧的感觉。正是这种心理上的恐怖,导致了近年来纸嫁衣和烟火等优秀SensorTower2022年上半年元宇宙游戏下载量已突破1。1亿智通财经APP获悉,据SensorTower最新报告指出,随着新冠疫情对于全球用户非接触式生活方式的推动,虚拟世界与元宇宙概念再一次成为移动市场增长热点。2020年,全球元宇宙应用
友情链接:快好找快生活快百科快传网中准网文好找聚热点快软网