ibatis 3.0 Dynamic Sql 设计解析(并与2.x的差异)

前段时间ibatis3.0发布出来了,迫不及待,将其源码下载拜读。相对ibatis 2.x来说,3.0已是完全改变。具体我就不在这细说,论坛中有一个帖子介绍了ibatis 3.0的新特征及使用。

      由于其他模块的源码我还未细读,在这篇中,先来讨论Dynamic Sql在ibatis 3.0中的实现并比较2.x对应模块的设计。

 

写在前头的话:

      其实如从设计模式应用角度去看待ibatis 3.0中Dynamic Sql的实现,这篇跟我的上篇(HtmlParser设计解析(1)-解析器模式)相同,都是使用Interpreter模式。

      这篇权当Interpreter模式的另一个demo,认我们体会这些开源项目中设计模式的使用。学习都是从模仿开始的,让 我们吸收高人们的经验,应用于我们实践项目需求中。

 

   从总结中提高:

   一、对比2.x中与3.0的Sqlmap中dynamic sql配置

   2.x:

Xml代码 复制代码
  1. <select id="dynamicGetAccountList" parameterClass="Account" resultClass="Account">    
  2.       select ACC_ID as id,   
  3.       ACC_FIRST_NAME as firstName,   
  4.       ACC_LAST_NAME as lastName,   
  5.       ACC_EMAIL as emailAddress from ACCOUNT   
  6.          
  7.     <dynamic prepend="WHERE">  
  8.       <isNotNull prepend="AND" property="emailAddress">  
  9.         ACC_EMAIL = #emailAddress#   
  10.       </isNotNull>  
  11.       <isNotNull property="idList" prepend=" or ACC_ID in ">      
  12.         <iterate property="idList" conjunction="," open="(" close=")" >      
  13.             #id#     
  14.         </iterate>      
  15.       </isNotNull>      
  16.     </dynamic>  
  17. </select>  
<select id="dynamicGetAccountList" parameterClass="Account" resultClass="Account"> 
      select ACC_ID as id,
      ACC_FIRST_NAME as firstName,
      ACC_LAST_NAME as lastName,
      ACC_EMAIL as emailAddress from ACCOUNT
	  
	<dynamic prepend="WHERE">
	  <isNotNull prepend="AND" property="emailAddress">
        ACC_EMAIL = #emailAddress#
      </isNotNull>
      <isNotNull property="idList" prepend=" or ACC_ID in ">   
		<iterate property="idList" conjunction="," open="(" close=")" >   
			#id#  
		</iterate>   
	  </isNotNull>   
    </dynamic>
</select>

 

   3.0:

Xml代码 复制代码
  1. <select id="dynamicGetAccountList" parameterType="Account" resultType="Account">  
  2.       select ACC_ID as id,   
  3.       ACC_FIRST_NAME as firstName,   
  4.       ACC_LAST_NAME as lastName,   
  5.       ACC_EMAIL as emailAddress from ACCOUNT   
  6.   
  7.     <where>  
  8.         <if test="emailAddress != null">ACC_EMAIL = #{emailAddress}</if>  
  9.         <if test="idList != null">  
  10.             or ACC_ID IN   
  11.             <foreach item="id" index="index" open="(" close=")" separator="," collection="idList">  
  12.                 #{idList[${index}]}   
  13.             </foreach>  
  14.        </if>  
  15.     </where>  
  16. </select>  
<select id="dynamicGetAccountList" parameterType="Account" resultType="Account">
	  select ACC_ID as id,
	  ACC_FIRST_NAME as firstName,
	  ACC_LAST_NAME as lastName,
	  ACC_EMAIL as emailAddress from ACCOUNT

	<where>
		<if test="emailAddress != null">ACC_EMAIL = #{emailAddress}</if>
		<if test="idList != null">
			or ACC_ID IN
			<foreach item="id" index="index" open="(" close=")" separator="," collection="idList">
				#{idList[${index}]}
			</foreach>
	   </if>
	</where>
</select>

      从上面这个简单的比较中,第一感觉3.0了中其dynamic sql更加简洁明了。

      其二,test="emailAddress != null" 添加了OGNL的解释支持,可以动态支持更多的判断,这将不限于原2.x中提供

的判断逻辑,更不需要为每个判断条件加个标签进行配置。

      例如:<if test="id > 10 && id < 20"> ACC_EMAIL = #{emailAddress}</if>

               <if test="Account.emailAddress != null "> ACC_EMAIL = #{emailAddress}</if> ……

 

   二、2.x Dynamic Sql的设计

 

   2.1、2.x中dynamic流程。

   这里帖出,我先前在分析ibatis 2.3时画的一个对dynamic sql的整体使用的时序图,可能会显得乱而复杂。

ibatis dynamic sequence

   2.2、主要类设计

       在这,我们只关注这几个类:XMLSqlSource、DynamicSql、SqlTagHandler (具体类结构图见后)

      XMLSqlSource:相当于一个工厂类,其核心方法parseDynamicTags(),用于解析sql Tag,并判断是否是动态SQL标签。如果true,返回一个DynamicSql对象并创建多个SqlChildt对象添加至动态SQL列表中(addChild());false,返回RawSql对象(简单的SQL语句) 。

     DynamicSql:核心的动态SQL类。其动态条件判断逻辑,参数映射等都发生在这个类中。

     SqlTagHandle:动态条件判断接口,其每个动态SQL标签对应其一个子类。

  接下来,我们具体看下在DynamicSql类中核心方法。

    DynamicSql:

Java代码 复制代码
  1. private void processBodyChildren(StatementScope statementScope, SqlTagContext ctx, Object parameterObject, Iterator localChildren, PrintWriter out) {   
  2.     while (localChildren.hasNext()) { //XMLSqlSource 生成的动态SQL列表   
  3.       SqlChild child = (SqlChild) localChildren.next();   
  4.       if (child instanceof SqlText) {   
  5.           ... ... //组装SQL语句及映射SQL参数   
  6.       } else if (child instanceof SqlTag) {   
  7.         SqlTag tag = (SqlTag) child;   
  8.         SqlTagHandler handler = tag.getHandler(); //得到动态SQL标签处理器   
  9.         int response = SqlTagHandler.INCLUDE_BODY;   
  10.         do {             
  11.           response = handler.doStartFragment(ctx, tag, parameterObject); //处理开始片段   
  12.           if (response != SqlTagHandler.SKIP_BODY) { //是否跳过,意思该判断的条件为false   
  13.             processBodyChildren(statementScope, ctx, parameterObject, tag.getChildren(), pw); //递归处理   
  14.             StringBuffer body = sw.getBuffer();   
  15.             response = handler.doEndFragment(ctx, tag, parameterObject, body); //处理结束片段   
  16.             handler.doPrepend(ctx, tag, parameterObject, body); //组装SQL   
  17.                
  18.           }   
  19.         } while (response == SqlTagHandler.REPEAT_BODY);   
  20.         ... ...    }   
  21. }  
private void processBodyChildren(StatementScope statementScope, SqlTagContext ctx, Object parameterObject, Iterator localChildren, PrintWriter out) {
    while (localChildren.hasNext()) { //XMLSqlSource 生成的动态SQL列表
      SqlChild child = (SqlChild) localChildren.next();
      if (child instanceof SqlText) {
          ... ... //组装SQL语句及映射SQL参数
      } else if (child instanceof SqlTag) {
        SqlTag tag = (SqlTag) child;
        SqlTagHandler handler = tag.getHandler(); //得到动态SQL标签处理器
        int response = SqlTagHandler.INCLUDE_BODY;
        do {          
          response = handler.doStartFragment(ctx, tag, parameterObject); //处理开始片段
          if (response != SqlTagHandler.SKIP_BODY) { //是否跳过,意思该判断的条件为false
            processBodyChildren(statementScope, ctx, parameterObject, tag.getChildren(), pw); //递归处理
            StringBuffer body = sw.getBuffer();
            response = handler.doEndFragment(ctx, tag, parameterObject, body); //处理结束片段
            handler.doPrepend(ctx, tag, parameterObject, body); //组装SQL
            
          }
        } while (response == SqlTagHandler.REPEAT_BODY);
		... ...    }
}

 

    2.3、SqlTagHandle设计

    首先看下SqlTagHandle处理类的结果图:


 

    ConditionalTagHandler:

Java代码 复制代码
  1. public abstract class ConditionalTagHandler extends BaseTagHandler {   
  2.   ... ...   
  3.   public abstract boolean isCondition(SqlTagContext ctx, SqlTag tag, Object parameterObject);   
  4.   
  5.   public int doStartFragment(SqlTagContext ctx, SqlTag tag, Object parameterObject) {   
  6.     ctx.pushRemoveFirstPrependMarker(tag);   
  7.     if (isCondition(ctx, tag, parameterObject)) {   
  8.       return SqlTagHandler.INCLUDE_BODY;   
  9.     } else {   
  10.       return SqlTagHandler.SKIP_BODY;   
  11.     }   
  12.   }   
  13.   ... ...   
  14. }  
public abstract class ConditionalTagHandler extends BaseTagHandler {
  ... ...
  public abstract boolean isCondition(SqlTagContext ctx, SqlTag tag, Object parameterObject);

  public int doStartFragment(SqlTagContext ctx, SqlTag tag, Object parameterObject) {
    ctx.pushRemoveFirstPrependMarker(tag);
    if (isCondition(ctx, tag, parameterObject)) {
      return SqlTagHandler.INCLUDE_BODY;
    } else {
      return SqlTagHandler.SKIP_BODY;
    }
  }
  ... ...
}

 

   IsNullTagHandler:

Java代码 复制代码
  1. public class IsNullTagHandler extends ConditionalTagHandler {   
  2.     private static final Probe PROBE = ProbeFactory.getProbe();   
  3.     public boolean isCondition(SqlTagContext ctx, SqlTag tag, Object parameterObject) {   
  4.         if (parameterObject == null) {   
  5.             return true;   
  6.         } else {   
  7.             String prop = getResolvedProperty(ctx, tag);   
  8.             Object value;   
  9.             if (prop != null) {   
  10.                 value = PROBE.getObject(parameterObject, prop);   
  11.             } else {   
  12.                 value = parameterObject;   
  13.             }   
  14.             return value == null;   
  15.         }   
  16.     }   
  17. }  
public class IsNullTagHandler extends ConditionalTagHandler {
	private static final Probe PROBE = ProbeFactory.getProbe();
	public boolean isCondition(SqlTagContext ctx, SqlTag tag, Object parameterObject) {
		if (parameterObject == null) {
			return true;
		} else {
			String prop = getResolvedProperty(ctx, tag);
			Object value;
			if (prop != null) {
				value = PROBE.getObject(parameterObject, prop);
			} else {
				value = parameterObject;
			}
			return value == null;
		}
	}
}

   至于其他的相关类,不在这列出了,有兴趣的可以找其源码了解下。

 

   2.4、总结ibatis 2.X Dynamic Sql 的设计

      从上面的分析中,可以体会出作者的dynamic sql这模块的设计思路。从装载sqlmap.xml中各sql配置(时序图中的1步),通过工厂创建DynamicSql和RawSql(时序图中的3步),然后分发之不同的处理器。

      在DynamicSql中则调用SqlTagHandle判断其条件(时序图中的10步)。而SqlTagHandle的设计使用策略者模式,让其不同的子类来处理这个判断逻辑。

      通过一系列的加工,最终组装一个Sql对象,将值set至MappedStatement(时序图中的14步)中,然后MappedStatement对象执行executeQueryWithCallback查询数据(时序图中的17步),这儿会调用先前组装的Sql对象(时序图中的19步)。至于这其中的细节已不在这篇的研究这内。

 

    三、3.0 Dynamic Sql的设计

           至于3.0其基本流程跟2.x是一样的,从装载  -> 参数映射 -> 执行SQL -> 返回结果。我们直接切入主题,分析是核心部分。先从一个简单的Dynamic Sql的测试用例开始。

 

   3.1、 测试用例

    dynamic sql test:

Java代码 复制代码
  1. @Test  
  2. public void shouldTrimWHEREInsteadOfORForSecondCondition() throws Exception {   
  3.  /* SELECT * FROM BLOG  
  4.     <where>  
  5.         <if test="id != false"> and ID = #{id} </if>  
  6.         <if test="name != false"> or NAME = #{name} </if>  
  7.     </where>  
  8.    */  
  9.     final String expected = "SELECT * FROM BLOG WHERE  NAME = ?";   
  10.     DynamicSqlSource source = createDynamicSqlSource(   
  11.             new TextSqlNode("SELECT * FROM BLOG"),    
  12.                 new WhereSqlNode(mixedContents(   
  13.                         new IfSqlNode(   
  14.                                 mixedContents(new TextSqlNode("   and ID = ?  ")),"false"), new IfSqlNode(mixedContents(new TextSqlNode("   or NAME = ?  ")), "true"))));   
  15.     BoundSql boundSql = source.getBoundSql(null);   
  16.     assertEquals(expected, boundSql.getSql());   
  17. }   
  18.   
  19. private DynamicSqlSource createDynamicSqlSource(SqlNode... contents)   
  20.         throws IOException, SQLException {   
  21.     createBlogDataSource();   
  22.     final String resource =  ".../MapperConfig.xml";   
  23.     final Reader reader = Resources.getResourceAsReader(resource);   
  24.     SqlSessionFactory sqlMapper = new SqlSessionFactoryBuilder()   
  25.             .build(reader);   
  26.     Configuration configuration = sqlMapper.getConfiguration();   
  27.     MixedSqlNode sqlNode = mixedContents(contents);   
  28.     return new DynamicSqlSource(configuration, sqlNode);   
  29. }   
  30.   
  31. private MixedSqlNode mixedContents(SqlNode... contents) {   
  32.     return new MixedSqlNode(Arrays.asList(contents));   
  33. }  
	@Test
	public void shouldTrimWHEREInsteadOfORForSecondCondition() throws Exception {
	 /*	SELECT * FROM BLOG
		<where>
			<if test="id != false"> and ID = #{id} </if>
			<if test="name != false"> or NAME = #{name} </if>
		</where>
	   */
		final String expected = "SELECT * FROM BLOG WHERE  NAME = ?";
		DynamicSqlSource source = createDynamicSqlSource(
				new TextSqlNode("SELECT * FROM BLOG"), 
					new WhereSqlNode(mixedContents(
							new IfSqlNode(
									mixedContents(new TextSqlNode("   and ID = ?  ")),"false"), new IfSqlNode(mixedContents(new TextSqlNode("   or NAME = ?  ")), "true"))));
		BoundSql boundSql = source.getBoundSql(null);
		assertEquals(expected, boundSql.getSql());
	}

	private DynamicSqlSource createDynamicSqlSource(SqlNode... contents)
			throws IOException, SQLException {
		createBlogDataSource();
		final String resource =  ".../MapperConfig.xml";
		final Reader reader = Resources.getResourceAsReader(resource);
		SqlSessionFactory sqlMapper = new SqlSessionFactoryBuilder()
				.build(reader);
		Configuration configuration = sqlMapper.getConfiguration();
		MixedSqlNode sqlNode = mixedContents(contents);
		return new DynamicSqlSource(configuration, sqlNode);
	}

	private MixedSqlNode mixedContents(SqlNode... contents) {
		return new MixedSqlNode(Arrays.asList(contents));
	}

  

  有经验的人,我想一眼就能看出其3.0中的设计思想,从Test中可以看出,或者我上一篇介绍的HtmlParser NodeFilter。

    YES,在ibatis 3.0 dynamic sql设计正是应用了解释器模式,替换了原在这种需求下相对显得笨拙的策略者模式。

 

   下面具体看下类结构图。

 

   3.2、类结构图

   SqlNode Class Diagram:

   SqlSource Class Diagram:

 

   3.3、配置文件的解析

   在这,我就顺便提下ibatis解析组件对dynamic sql的解析方式,以代码见分晓吧。

 

   XMLStatementBuilder:

Java代码 复制代码
  1. public void parseStatementNode(XNode context) {   
  2.                ...  ...   
  3.     List<SqlNode> contents = parseDynamicTags(context);   
  4.     MixedSqlNode rootSqlNode = new MixedSqlNode(contents);//再次包装dynamic sql处理链   
  5.     SqlSource sqlSource = new DynamicSqlSource(configuration, rootSqlNode); //默认初始化DynamicSqlSource   
  6.                ... ...   
  7.     builderAssistant.addMappedStatement(id, sqlSource, statementType,   
  8.             sqlCommandType, fetchSize, timeout, parameterMap,   
  9.             parameterTypeClass, resultMap, resultTypeClass,   
  10.             resultSetTypeEnum, flushCache, useCache, keyGenerator,   
  11.             keyProperty); //将解析的所有属性构建成相应的对象存入全局的申明对象(MappedStatement)中,后面只传递该对象。   
  12. }   
  13.   
  14. private List<SqlNode> parseDynamicTags(XNode node) {   
  15.     List<SqlNode> contents = new ArrayList<SqlNode>();   
  16.     NodeList children = node.getNode().getChildNodes();   
  17.     for (int i = 0; i < children.getLength(); i++) {   
  18.         XNode child = node.newXNode(children.item(i));   
  19.         String nodeName = child.getNode().getNodeName();   
  20.         if (child.getNode().getNodeType() == Node.CDATA_SECTION_NODE   
  21.                 || child.getNode().getNodeType() == Node.TEXT_NODE) {   
  22.             String data = child.getStringBody("");   
  23.             contents.add(new TextSqlNode(data));   
  24.         } else {   
  25.             NodeHandler handler = nodeHandlers.get(nodeName);   
  26.             if (handler == null) {   
  27.                 throw new BuilderException("Unknown element <" + nodeName "> in SQL statement.");   
  28.             }   
  29.             handler.handleNode(child, contents);   
  30.         }   
  31.     }   
  32.     return contents;   
  33. }            
  34. private Map<String, NodeHandler> nodeHandlers = new HashMap<String, NodeHandler>() {   
  35.     {   
  36.         put("where"new WhereHandler());   
  37.         put("set"new SetHandler());   
  38.         put("foreach"new ForEachHandler());   
  39.         put("if"new IfHandler());   
  40.         ... ...   
  41.     }   
  42. };   
  43. private interface NodeHandler {   
  44.     void handleNode(XNode nodeToHandle, List<SqlNode> targetContents);   
  45. }   
  46. private class WhereHandler implements NodeHandler {   
  47.     public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {   
  48.         List<SqlNode> contents = parseDynamicTags(nodeToHandle);// 遍历   
  49.         MixedSqlNode mixedSqlNode = new MixedSqlNode(contents);//对应测试用例中的mixedContents方法   
  50.         WhereSqlNode where = new WhereSqlNode(mixedSqlNode);   
  51.         targetContents.add(where);   
  52.     }   
  53. }   
  54. private class IfHandler implements NodeHandler {   
  55.     public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {   
  56.         List<SqlNode> contents = parseDynamicTags(nodeToHandle);//遍历   
  57.         MixedSqlNode mixedSqlNode = new MixedSqlNode(contents);   
  58.         String test = nodeToHandle.getStringAttribute("test");   
  59.         IfSqlNode ifSqlNode = new IfSqlNode(mixedSqlNode, test);//初始化对应的处理器   
  60.         targetContents.add(ifSqlNode);//   
  61.     }   
  62. // 其他的Handle详见ibatis源码~  
	public void parseStatementNode(XNode context) {
                ...  ...
		List<SqlNode> contents = parseDynamicTags(context);
		MixedSqlNode rootSqlNode = new MixedSqlNode(contents);//再次包装dynamic sql处理链
		SqlSource sqlSource = new DynamicSqlSource(configuration, rootSqlNode); //默认初始化DynamicSqlSource
                ... ...
		builderAssistant.addMappedStatement(id, sqlSource, statementType,
				sqlCommandType, fetchSize, timeout, parameterMap,
				parameterTypeClass, resultMap, resultTypeClass,
				resultSetTypeEnum, flushCache, useCache, keyGenerator,
				keyProperty); //将解析的所有属性构建成相应的对象存入全局的申明对象(MappedStatement)中,后面只传递该对象。
	}

	private List<SqlNode> parseDynamicTags(XNode node) {
		List<SqlNode> contents = new ArrayList<SqlNode>();
		NodeList children = node.getNode().getChildNodes();
		for (int i = 0; i < children.getLength(); i++) {
			XNode child = node.newXNode(children.item(i));
			String nodeName = child.getNode().getNodeName();
			if (child.getNode().getNodeType() == Node.CDATA_SECTION_NODE
					|| child.getNode().getNodeType() == Node.TEXT_NODE) {
				String data = child.getStringBody("");
				contents.add(new TextSqlNode(data));
			} else {
				NodeHandler handler = nodeHandlers.get(nodeName);
				if (handler == null) {
					throw new BuilderException("Unknown element <" + nodeName "> in SQL statement.");
				}
				handler.handleNode(child, contents);
			}
		}
		return contents;
	}         
	private Map<String, NodeHandler> nodeHandlers = new HashMap<String, NodeHandler>() {
		{
			put("where", new WhereHandler());
			put("set", new SetHandler());
			put("foreach", new ForEachHandler());
			put("if", new IfHandler());
			... ...
		}
	};
	private interface NodeHandler {
		void handleNode(XNode nodeToHandle, List<SqlNode> targetContents);
	}
	private class WhereHandler implements NodeHandler {
		public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
			List<SqlNode> contents = parseDynamicTags(nodeToHandle);// 遍历
			MixedSqlNode mixedSqlNode = new MixedSqlNode(contents);//对应测试用例中的mixedContents方法
			WhereSqlNode where = new WhereSqlNode(mixedSqlNode);
			targetContents.add(where);
		}
	}
	private class IfHandler implements NodeHandler {
		public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
			List<SqlNode> contents = parseDynamicTags(nodeToHandle);//遍历
			MixedSqlNode mixedSqlNode = new MixedSqlNode(contents);
			String test = nodeToHandle.getStringAttribute("test");
			IfSqlNode ifSqlNode = new IfSqlNode(mixedSqlNode, test);//初始化对应的处理器
			targetContents.add(ifSqlNode);//
		}
	} // 其他的Handle详见ibatis源码~

    上面是其解析代码的一部分,我想从这几行代码中,可以看出作者的思想了(遍历XML各节点,以节点名查找相应对应的处理器,分发之该处理器执行"业务分析" — 策略者模式,这样在XML中定义了多少标签,这里就需要多少个类与之对应,但如果策略类太多,这种方式就显得笨拙了)。

 

    以下就是其核心类的一部分源码,先看再说。

    3.4、DynamicSqlSource(核心类)

Java代码 复制代码
  1. public class DynamicSqlSource implements SqlSource {   
  2.     public DynamicSqlSource(Configuration configuration, SqlNode rootSqlNode) {   
  3.         this.configuration = configuration;   
  4.         this.rootSqlNode = rootSqlNode;   
  5.     }   
  6.     public BoundSql getBoundSql(Object parameterObject) {   
  7.         DynamicContext context = new DynamicContext(parameterObject);//组装后的结果存储类   
  8.         rootSqlNode.apply(context);//调用SqlNode解释sql,并组装成完整的sql(SqlNode的客户端调用就在这)   
  9.         SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);   
  10.         Class parameterType = parameterObject == null ? Object.class : parameterObject.getClass();   
  11.         SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType);   
  12.         BoundSql boundSql = sqlSource.getBoundSql(parameterObject);   
  13.         for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) {   
  14.             boundSql.setAdditionalParameter(entry.getKey(), entry.getValue());   
  15.         }   
  16.         return boundSql;   
  17.     }   
  18. }  
public class DynamicSqlSource implements SqlSource {
	public DynamicSqlSource(Configuration configuration, SqlNode rootSqlNode) {
		this.configuration = configuration;
		this.rootSqlNode = rootSqlNode;
	}
	public BoundSql getBoundSql(Object parameterObject) {
		DynamicContext context = new DynamicContext(parameterObject);//组装后的结果存储类
		rootSqlNode.apply(context);//调用SqlNode解释sql,并组装成完整的sql(SqlNode的客户端调用就在这)
		SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
		Class parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
		SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType);
		BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
		for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) {
			boundSql.setAdditionalParameter(entry.getKey(), entry.getValue());
		}
		return boundSql;
	}
}

 

   3.5、SqlNode

 

Java代码 复制代码
  1. public interface SqlNode {   
  2.     public boolean apply(DynamicContext context);   
  3. }  
public interface SqlNode {
	public boolean apply(DynamicContext context);
}

 

    MixedSqlNode.class

Java代码 复制代码
  1. public class MixedSqlNode implements SqlNode {   
  2.         ... ....   
  3.     public boolean apply(DynamicContext context) {   
  4.         //遍历组装的解析内容   
  5.         for (SqlNode sqlNode : contents) {    
  6.             // 转发至相关解释器处理   
  7.             sqlNode.apply(context);    
  8.         }   
  9.         return true;   
  10.     }   
  11. }  
public class MixedSqlNode implements SqlNode {
        ... ....
	public boolean apply(DynamicContext context) {
		//遍历组装的解析内容
		for (SqlNode sqlNode : contents) { 
			// 转发至相关解释器处理
			sqlNode.apply(context); 
		}
		return true;
	}
}

   IfSqlNode.class

Java代码 复制代码
  1. public class IfSqlNode implements SqlNode {   
  2.        ... ...   
  3.     public IfSqlNode(SqlNode contents, String test) {   
  4.         this.test = test;   
  5.         this.contents = contents;   
  6.         this.evaluator = new ExpressionEvaluator();   
  7.     }   
  8.   
  9.     public boolean apply(DynamicContext context) {   
  10.         if (evaluator.evaluateBoolean(test, context.getBindings())) {//OGNL Expressions   
  11.             contents.apply(context);   
  12.             return true//   
  13.         }   
  14.         return false;   
  15.     }   
  16. }  
public class IfSqlNode implements SqlNode {
       ... ...
	public IfSqlNode(SqlNode contents, String test) {
		this.test = test;
		this.contents = contents;
		this.evaluator = new ExpressionEvaluator();
	}

	public boolean apply(DynamicContext context) {
		if (evaluator.evaluateBoolean(test, context.getBindings())) {//OGNL Expressions
			contents.apply(context);
			return true; //
		}
		return false;
	}
}

   TextSqlNode.class

Java代码 复制代码
  1. public class TextSqlNode implements SqlNode {   
  2.     private String text;   
  3.   
  4.     public TextSqlNode(String text) {   
  5.         this.text = text;   
  6.     }   
  7.   
  8.     
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值