您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 销售管理 > ibatis 3.0 Dynamic Sql 设计解析(并与2.x的差异)
ibatis3.0DynamicSql设计解析(并与2.x的差异)前段时间ibatis3.0发布出来了,迫不及待,将其源码下载拜读。相对ibatis2.x来说,3.0已是完全改变。具体我就不在这细说,论坛中有一个帖子介绍了ibatis3.0的新特征及使用。由于其他模块的源码我还未细读,在这篇中,先来讨论DynamicSql在ibatis3.0中的实现并比较2.x对应模块的设计。写在前头的话:其实如从设计模式应用角度去看待ibatis3.0中DynamicSql的实现,这篇跟我的上篇(HtmlParser设计解析(1)-解析器模式)相同,都是使用Interpreter模式。这篇权当Interpreter模式的另一个demo,认我们体会这些开源项目中设计模式的使用。学习都是从模仿开始的,让我们吸收高人们的经验,应用于我们实践项目需求中。从总结中提高:一、对比2.x中与3.0的Sqlmap中dynamicsql配置2.x:Xml代码1.selectid=dynamicGetAccountListparameterClass=AccountresultClass=Account2.selectACC_IDasid,3.ACC_FIRST_NAMEasfirstName,4.ACC_LAST_NAMEaslastName,5.ACC_EMAILasemailAddressfromACCOUNT6.7.dynamicprepend=WHERE8.isNotNullprepend=ANDproperty=emailAddress9.ACC_EMAIL=#emailAddress#10./isNotNull11.isNotNullproperty=idListprepend=orACC_IDin12.iterateproperty=idListconjunction=,open=(close=)13.#id#14./iterate15./isNotNull16./dynamic17./select3.0:Xml代码1.selectid=dynamicGetAccountListparameterType=AccountresultType=Account2.selectACC_IDasid,3.ACC_FIRST_NAMEasfirstName,4.ACC_LAST_NAMEaslastName,5.ACC_EMAILasemailAddressfromACCOUNT6.7.where8.iftest=emailAddress!=nullACC_EMAIL=#{emailAddress}/if9.iftest=idList!=null10.orACC_IDIN11.foreachitem=idindex=indexopen=(close=)separator=,collection=idList12.#{idList[${index}]}13./foreach14./if15./where16./select从上面这个简单的比较中,第一感觉3.0了中其dynamicsql更加简洁明了。其二,test=emailAddress!=null添加了OGNL的解释支持,可以动态支持更多的判断,这将不限于原2.x中提供的判断逻辑,更不需要为每个判断条件加个标签进行配置。例如:iftest=id10&&id20ACC_EMAIL=#{emailAddress}/ififtest=Account.emailAddress!=nullACC_EMAIL=#{emailAddress}/if……二、2.xDynamicSql的设计2.1、2.x中dynamic流程。这里帖出,我先前在分析ibatis2.3时画的一个对dynamicsql的整体使用的时序图,可能会显得乱而复杂。2.2、主要类设计在这,我们只关注这几个类:XMLSqlSource、DynamicSql、SqlTagHandler(具体类结构图见后)XMLSqlSource:相当于一个工厂类,其核心方法parseDynamicTags(),用于解析sqlTag,并判断是否是动态SQL标签。如果true,返回一个DynamicSql对象并创建多个SqlChildt对象添加至动态SQL列表中(addChild());false,返回RawSql对象(简单的SQL语句)。DynamicSql:核心的动态SQL类。其动态条件判断逻辑,参数映射等都发生在这个类中。SqlTagHandle:动态条件判断接口,其每个动态SQL标签对应其一个子类。接下来,我们具体看下在DynamicSql类中核心方法。DynamicSql:Java代码1.privatevoidprocessBodyChildren(StatementScopestatementScope,SqlTagContextctx,ObjectparameterObject,IteratorlocalChildren,PrintWriterout){2.while(localChildren.hasNext()){//XMLSqlSource生成的动态SQL列表3.SqlChildchild=(SqlChild)localChildren.next();4.if(childinstanceofSqlText){5.......//组装SQL语句及映射SQL参数6.}elseif(childinstanceofSqlTag){7.SqlTagtag=(SqlTag)child;8.SqlTagHandlerhandler=tag.getHandler();//得到动态SQL标签处理器9.intresponse=SqlTagHandler.INCLUDE_BODY;10.do{11.response=handler.doStartFragment(ctx,tag,parameterObject);//处理开始片段12.if(response!=SqlTagHandler.SKIP_BODY){//是否跳过,意思该判断的条件为false13.processBodyChildren(statementScope,ctx,parameterObject,tag.getChildren(),pw);//递归处理14.StringBufferbody=sw.getBuffer();15.response=handler.doEndFragment(ctx,tag,parameterObject,body);//处理结束片段16.handler.doPrepend(ctx,tag,parameterObject,body);//组装SQL17.18.}19.}while(response==SqlTagHandler.REPEAT_BODY);20.......}21.}2.3、SqlTagHandle设计首先看下SqlTagHandle处理类的结果图:ConditionalTagHandler:Java代码1.publicabstractclassConditionalTagHandlerextendsBaseTagHandler{2.......3.publicabstractbooleanisCondition(SqlTagContextctx,SqlTagtag,ObjectparameterObject);4.5.publicintdoStartFragment(SqlTagContextctx,SqlTagtag,ObjectparameterObject){6.ctx.pushRemoveFirstPrependMarker(tag);7.if(isCondition(ctx,tag,parameterObject)){8.returnSqlTagHandler.INCLUDE_BODY;9.}else{10.returnSqlTagHandler.SKIP_BODY;11.}12.}13.......14.}IsNullTagHandler:Java代码1.publicclassIsNullTagHandlerextendsConditionalTagHandler{2.privatestaticfinalProbePROBE=ProbeFactory.getProbe();3.publicbooleanisCondition(SqlTagContextctx,SqlTagtag,ObjectparameterObject){4.if(parameterObject==null){5.returntrue;6.}else{7.Stringprop=getResolvedProperty(ctx,tag);8.Objectvalue;9.if(prop!=null){10.value=PROBE.getObject(parameterObject,prop);11.}else{12.value=parameterObject;13.}14.returnvalue==null;15.}16.}17.}至于其他的相关类,不在这列出了,有兴趣的可以找其源码了解下。2.4、总结ibatis2.XDynamicSql的设计从上面的分析中,可以体会出作者的dynamicsql这模块的设计思路。从装载sqlmap.xml中各sql配置(时序图中的1步),通过工厂创建DynamicSql和RawSql(时序图中的3步),然后分发之不同的处理器。在DynamicSql中则调用SqlTagHandle判断其条件(时序图中的10步)。而SqlTagHandle的设计使用策略者模式,让其不同的子类来处理这个判断逻辑。通过一系列的加工,昀终组装一个Sql对象,将值set至MappedStatement(时序图中的14步)中,然后MappedStatement对象执行executeQueryWithCallback查询数据(时序图中的17步),这儿会调用先前组装的Sql对象(时序图中的19步)。至于这其中的细节已不在这篇的研究这内。三、3.0DynamicSql的设计至于3.0其基本流程跟2.x是一样的,从装载-参数映射-执行SQL-返回结果。我们直接切入主题,分析是核心部分。先从一个简单的DynamicSql的测试用例开始。3.1、测试用例dynamicsqltest:Java代码1.@Test2.publicvoidshouldTrimWHEREInsteadOfORForSecondCondition()throwsException{3./*SELECT*FROMBLOG4.where5.iftest=id!=falseandID=#{id}/if6.iftest=name!=falseorNAME=#{name}/if7./where8.*/9.finalStringexpected=SELECT*FROMBLOGWHERENAME=?;10.DynamicSqlSourcesource=createDynamicSqlSource(11.newTextSqlNode(SELECT*FROMBLOG),12.newWhereSqlNode(mixedContents(13.newIfSqlNode(14.mixedContents(newTextSqlNode(andID=?)),false),newIfSqlNode(mixedContents(newTextSqlNode(orNAME=?)),true))));15.BoundSqlboundSql=source.getBoundSql(null);16.assertEquals(expected,boundSql.getSql());17.}18.19.privateDyn
本文标题:ibatis 3.0 Dynamic Sql 设计解析(并与2.x的差异)
链接地址:https://www.777doc.com/doc-5378546 .html