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.     
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章