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

MyBatis执行SQL的原理

  在开发中使用mybatis,是将Mapper接口生成的代理类存入到springIOC容器中。然后,通过注解获取代理对象,调用对应接口方法,间接调用到mapperxml中的SQL。
  如果想了解mybatis是如何通过接口实现SQL操作可以看一下这个:https:www。toutiao。comarticle7206541912168268343
  一般接口都会有入参,和返回对象。那么mybatis是如何进行封装的呢?
  mapperxml文件中的语句经常会使用一些标签if、foreach、set、where等,是如何实现的呢?
  Mybatis参数的解析
  参数解析这一步骤,通常是在执行SQL语句之前就要完成的,因此,需要查看SQL执行之前的代码。问题是从哪里开始查看源码呢?既然不知道具体是哪里进行了参数解析,那就从调用代理对象开始。
  代理对象调用方法执行MapperProxy。invoke方法,MapperProxy。invoke方法中调用MapperProxy。cachedInvoker方法,并且该方法中创建一个MapperMethod实例对象。
  MapperMethod对象中有两个成员常量,SqlCommand和MethodSignature对象。后面会用到。
  最终MapperProxy。cachedInvoker方法返回一个PlainMethodInvoker对象,接着PlainMethodInvoker对象调用自己的invoke方法(注意:这就是一个invoke方法,跟代理没关系,不要被迷惑了)
  调用方法后,执行MapperMethod对象的execute方法。该方法中
  method。convertArgsToSqlCommandParam(args),就是我们要找的参数解析方法。
  这块代码可以不看。publicObjectexecute(SqlSessionsqlSession,Object〔〕args){Objectresult;switch(command。getType()){caseINSERT:{Objectparammethod。convertArgsToSqlCommandParam(args);resultrowCountResult(sqlSession。insert(command。getName(),param));break;}caseUPDATE:{Objectparammethod。convertArgsToSqlCommandParam(args);resultrowCountResult(sqlSession。update(command。getName(),param));break;}caseDELETE:{Objectparammethod。convertArgsToSqlCommandParam(args);resultrowCountResult(sqlSession。delete(command。getName(),param));break;}caseSELECT:if(method。returnsVoid()method。hasResultHandler()){executeWithResultHandler(sqlSession,args);resultnull;}elseif(method。returnsMany()){resultexecuteForMany(sqlSession,args);}elseif(method。returnsMap()){resultexecuteForMap(sqlSession,args);}elseif(method。returnsCursor()){resultexecuteForCursor(sqlSession,args);}else{Objectparammethod。convertArgsToSqlCommandParam(args);resultsqlSession。selectOne(command。getName(),param);if(method。returnsOptional()(resultnull!method。getReturnType()。equals(result。getClass()))){resultOptional。ofNullable(result);}}break;caseFLUSH:resultsqlSession。flushStatements();break;default:thrownewBindingException(Unknownexecutionmethodfor:command。getName());}if(resultnullmethod。getReturnType()。isPrimitive()!method。returnsVoid()){thrownewBindingException(Mappermethodcommand。getName()attemptedtoreturnnullfromamethodwithaprimitivereturntype(method。getReturnType())。);}returnresult;}
  convertArgsToSqlCommandParam方法,MethodSignature对象是创建MapperMethod时一个成员常量。
  ParamNameResolver是MethodSignature中的一个成员常量。
  ParamNameResolver对象中ParamNameResolver方法。该方法获取带有param注解的参数。
  ParamNameResolver是用来解析param类型的publicParamNameResolver(Configurationconfig,Methodmethod){默认使用实际参数名this。useActualParamNameconfig。isUseActualParamName();finalClasslt;?〔〕paramTypesmethod。getParameterTypes();finalAnnotation〔〕〔〕paramAnnotationsmethod。getParameterAnnotations();finalSortedMapInteger,StringmapnewTreeMap();intparamCountparamAnnotations。length;getnamesfromParamannotations获取Param注解的参数for(intparamIndex0;paramIndexparamCount;paramIndex){if(isSpecialParameter(paramTypes〔paramIndex〕)){skipspecialparameterscontinue;}Stringnamenull;for(Annotationannotation:paramAnnotations〔paramIndex〕){if(annotationinstanceofParam){hasParamAnnotationtrue;name((Param)annotation)。value();break;}}if(namenull){Paramwasnotspecified。if(useActualParamName){namegetActualParamName(method,paramIndex);}if(namenull){usetheparameterindexasthename(0,1,。。。)gcodeissue71nameString。valueOf(map。size());}}map。put(paramIndex,name);}namesCollections。unmodifiableSortedMap(map);}
  用来解析实体参数(param1,param2,。。。)publicObjectgetNamedParams(Object〔〕args){finalintparamCountnames。size();if(argsnullparamCount0){returnnull;}如果只有一个参数,并且没有使用Param注解,就直接返回第一个参数elseif(!hasParamAnnotationparamCount1){Objectvalueargs〔names。firstKey()〕;returnwrapToMapIfCollection(value,useActualParamName?names。get(0):null);}有多个参数,则封装成一个map,key为参数参数名称,参数使用Param注解,名称就是注解中的值,否则key为arg0、arg1这种类型,同时,一定含有key为param1、param2的参数,值就是传入的值else{finalMapString,ObjectparamnewParamMap();inti0;for(Map。EntryInteger,Stringentry:names。entrySet()){没有Param注解,key为arg0、arg1这种类型param。put(entry。getValue(),args〔entry。getKey()〕);addgenericparamnames(param1,param2,。。。)finalStringgenericParamNameGENERICNAMEPREFIX(i1);ensurenottooverwriteparameternamedwithParamif(!names。containsValue(genericParamName)){param。put(genericParamName,args〔entry。getKey()〕);}i;}returnparam;}}
  小结:
  ParamNameResolver对象解析参数,两种方法:
  ParamNameResolver方法:解析形参,判断是否使用了Param注解。
  getNamedParams方法:封装实参,如果只有一个,并且没有使用Param注解,就直接返回第一个参数值,否则封装成map。多个参数,key为参数参数名称,使用Param注解,key值就是注解中的值,否则key为arg0、arg1这种类型,并且,一定含有key为param1、param2的参数,作为值传入。
  上面的这一部分主要是将参数解析。
  Mybatis解析好的参与SQL整合
  参数解析完成后,执行SqlSession中的方法。
  以selectList方法为例,首先获取MappedStatement对象,给对象包含SQL。
  wrapCollection(parameter)方法对解析后的参数进行了再次封装。
  对集合、数组、列表进行了二次封装,其他类型原样返回。
  执行executor。query(ms,wrapCollection(parameter),rowBounds,handler)代码后,进入BaseExecutor类中query方法。
  BoundSqlboundSqlms。getBoundSql(parameter);
  通过mappedStatement对象,获取BoundSql对象。
  然后,根据mappedStatement成员变量sqlSource调用getBoundSql。BoundSqlboundSqlsqlSource。getBoundSql(parameterObject);
  BoundSql语句的解析主要是通过对{}字符的解析,将其替换成?。{}中的key属性以及相应的参数映射,比如javaType、jdbcType等信息均保存至BoundSql的parameterMappings属性中。BoundSql类中的成员:
  ParameterObject:传入的参数。
  一个参数对象时:为该参数的类型;
  多个参数对象时:为ParamMap对象。
  ParameterMapping:{name}形式的引用变量,变量会在解析Mapper。xml文件中的语句时,就被替换成占位符?。ParameterMapping类记录对应的变量信息。
  additionalParameters:使用Criteria对象的sql。
  MetaObject:Mybatis在sql参数设置和结果集映射里经常使用到这个对象。
  DynamicSqlSource或者RowSqlSource,前者表示动态SQL,后者表示静态SQL。
  动态SQL:行该sql相关操作的时候才根据传入的参数进行解析。(mybatis标签if、where等)
  以StaticSqlSource为例:
  getBoundSql直接返回BoundSql对象。
  代码返回到:BaseExecutor类query方法中。
  query方法调用queryFromDatabase方法,queryFromDatabase再调用
  doQuery(ms,parameter,rowBounds,resultHandler,boundSql)方法。
  doQuery方法中prepareStatement就是给预编译SQL进行赋值的。OverridepublicEListEdoQuery(MappedStatementms,Objectparameter,RowBoundsrowBounds,ResultHandlerresultHandler,BoundSqlboundSql)throwsSQLException{Statementstmtnull;try{Configurationconfigurationms。getConfiguration();StatementHandlerhandlerconfiguration。newStatementHandler(wrapper,ms,parameter,rowBounds,resultHandler,boundSql);预编译sql,并且给参数赋值stmtprepareStatement(handler,ms。getStatementLog());returnhandler。query(stmt,resultHandler);}finally{closeStatement(stmt);}}
  prepareStatement方法中handler。parameterize(stmt)就是设置参数值。
  调用PreparedStatementHandler类的parameterize方法。
  parameterize方法中的parameterHandler。setParameters((PreparedStatement)statement)调用DefaultParameterHandlersetParameters方法。
  typeHandler。setParameter(ps,i1,value,jdbcType);
  千辛万苦终于是把解析的参数与SQL语句进行融合了。
  本篇篇幅有点长,后期拆分一下。

5年2。54亿!拿来马上签!不学詹姆斯和杜兰特,约基奇又要创掘金首轮14被勇士淘汰,结束了本赛季。第五场比赛结束后,约基奇与库里进行了拥抱,很多球迷开始猜测,约基奇会不会像的杜兰特一样,打不过就加入。过去3年,掘金成绩是一年比一年……喝酒会影响血糖吗?喝酒会影响体检结果吗?大家在体检之前都会听到医生说前几天不要喝酒,要控制饮食清淡,这对很多体检项目有影响。下面5号网小编给大家讲讲喝酒会影响血糖吗?喝酒会影响体检结果吗?喝酒会影响血糖吗喝酒肯……ps5的性能真没那么强例如ps5所谓的4k分辨率是有水分的,有动态分辨率或棋盘渲染。目前能原生4k60的游戏非常少,除了死亡搁浅原神还有吗?大部分都是动态4k60、光追2k30。在加入了fsr2。0……海底捞人均消费多少钱一位海底捞回应毛肚缩水海底捞是现在很多人都喜欢去的火锅店,听说它的消费是有些高的,那么具体的海底捞人均消费多少钱一位?海底捞人均消费多少钱一位海底捞火锅一般情况人均消费70100元。海底捞所有……冬天洗澡用什么取暖?冬天浴室用暖风机好吗?一般家里冬季洗澡的时候,都会开启浴霸或暖风机等保暖机器。不少人困惑了。冬天洗澡用什么取暖呢?关于,冬天洗澡用什么取暖?冬天浴室用暖风机好吗?5号网小编来为您一一解答!冬天……螃蟹可以带上高铁吗螃蟹为什么不能带上高铁螃蟹是我们大家都很熟悉的一种食物,而现在也是吃螃蟹的季节,而同时我们大家都知道高铁上是不可以携带活物的,那么螃蟹可以带上高铁吗?螃蟹为什么不能带上高铁?螃蟹可以带上高铁吗……爆炸桃子可以吃吗爆炸桃是新品种吗有时候买桃子会发现一些爆炸桃,而且还不是一个两个的,这个爆炸桃是属于新的品种吗?这爆炸桃可以吃吗?爆炸桃子可以吃吗强烈建议扔掉不要吃了。桃开裂的现象人称桃裂果病,但是桃裂……五代元老赖亚文排球传奇人生!赖亚文作为中国女排功勋球员,十年的国家队生涯,获得四个世界亚军,二个世界季军,五个亚锦赛冠军,二个亚运会冠军,她的运动生涯堪称传奇。国家队十年生涯,虽然没有获得世界冠军,……货运飞船刚到,俄飞船又泄漏,还是同样位置,国际空间站险象环生俄罗斯11日发射了进步号MS22货运飞船,不过在MS22宇宙飞船和国际空间站对接之后,却有噩耗传来,原本和国际空间站对接的进步号MS21货运飞船出现了散热系统的泄漏问题。面对进……是欲壑难平?还是另有原因?通过刘强东案,我们能看到些什么?近日,刘强东涉嫌性侵案又起波澜。有媒体爆料称此案将在美国举行公开听证会。原本我们以为这件事会不了了之了,但是随着美国警方案件重启调查……火灾蔓延的途径是火灾的危害火灾也是我们大家都很熟悉的一种灾害,对我们的影响是非常大的,并且导致火灾的原因是有很多的,那么我们便要了解一下火灾蔓延的途径是?火灾的危害?火灾蔓延的途径是火灾发生时热量……我们去哪里旅游?疏影横斜水清浅,暗香浮动月黄昏。一川烟草,满城风絮,梅子黄时雨。我们知道了为什么要去旅游,下来就要面临旅游地方的选择了,到底我们去哪里旅游呢?这就是我们今天要聊的旅游分类……
早安云南银都水乡,遇见大理的另一种生活山水田园,小城故事,星罗棋布的泉潭里,涌动着高原水乡的韵味,叮当作响的小锤声,敲打着新华银器的神采鹤庆的模样,是将风景、人文、历史、文化融于一体的精彩,总是能够让人一见倾心。……数读骑行徒步露营火了轻户外如何占领年轻人的假期?当天去、当天回的一日游旅行产品在国庆假期热度高涨,露营经济继续红火,短程、多次出行的即兴度假模式成为年轻人旅游新风尚,这届年轻人说走就走的度假距离越来越近,也越来越绿色和环保。……古滇国遗迹阿加尔塔长廊的发现,地心文明可能真实存在?很多科幻迷一直认为,我们脚下的地球内部存在着一个地下世界,地下世界里可能存在着地下的人,也可能存在着地下的文明。空心地球科学家计算得出,目前地球的重量为60万亿亿吨……10分赢青岛!高登首秀12中2,廖三宁116,外援失准让刘维7868!CBA季前赛,北控队一路领先拿下青岛队,迎来新赛季的一个小的开门红。今年夏天北控队调整幅度不大,阵容本来已经比较完善,只要规避好伤病即可,马布里关键的引援是签下了高登……广东不起眼的县城,GDP很低却有着中国唯一的县级中超球队我的小家和大家Hello,大家好,这里是xiang浩看世界。足球作为世界第一运动,在我国却始终没有得到进步和有效的推广,在一系列的赛事之中,最近的国足都是作为一个参赛者、……中超0结束连胜,广州城3场不胜北京时间10月8日,中超第22轮的较量中,沧州雄狮坐镇海口对阵广州城。上半场比赛,两队仅有3次射门,而且无一命中目标;下半场比赛,吉列尔梅伤退。全场比赛,两队毫无进攻欲望,只有……让你的皮肤看起来更年轻的抗衰老食物你的皮肤健康不仅取决于你的护肤程序,而且还取决于你所食用的食物。正如他们所说的吃什么就是什么。你的饮食对你的外表起着重要作用。你吃的食物越健康,你的皮肤就越健康。如果你想……地理位置再差劲,只要抓住机遇就能翻身,早期江西就是个典型头条创作挑战赛江西鄱阳湖观鸟节文史君对江西的最初印象,来自唐代王勃的《滕王阁序》,豫章故郡,洪都新府。星分翼轸,地接衡庐。襟三江而带五湖,控蛮荆而引瓯越。物华天宝,……CBA最新积分榜北京42分暴击福建,攀升第四,新疆击溃宁波排北京时间12月19日,CBA常规赛第15轮继续进行,在最新结束的两场比赛中,北京12381大胜福建,新疆10285轻取宁波,目前在最新的积分榜上,北京拿到两连胜攀升第四,新疆排……足球小知识什么叫越位?相信很多看了昨天1122晚上18点阿根廷VS沙特阿拉伯的世界杯比赛的朋友都有一个疑问:啥是越位?昨晚阿根廷对沙特的比赛中,阿根廷队上半场就被吹罚了7次越位,其中包括3个进……关于微信朋友圈张小龙曾发布一组数据:平均每天有10。9亿人打开微信,有3。3亿人进行视频通话,有7。8亿人打开了朋友圈,可是只有1。2亿人发朋友圈。在成年人的世界,位置不同,视野不同,……散文慢慢行,内心安静,走过人生岁月作者:子墨一缕阳光,寂静了时光,一缕晚风,吹薄了季节。阳光隐去,季节的风有点轻寒,悄悄而来,却让寒意漫过岁月的河岸,凋零了几片落叶,随风穿过时光的缝隙,落下几点沧桑。……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网