mybati(ibatis)中的动态sql 的详解

ibatis的文档中,关于动态SQL的举例如下: 
Java代码   收藏代码
  1. "someName" parameterClass="Account" resultMap="account-result" >  
  2.   select * from ACCOUNT  
  3.   "where">  
  4.     "and" property="id" compareValue="0">  
  5.       ACC_ID = #id#  
  6.       
  7.     "and" property="lastName">  
  8.       ACC_LAST_NAME = #lastName#  
  9.       
  10.     
  11. order by ACC_LAST_NAME  
  12.   


当需要使用根据传入参数的值来动态组装SQL时,可以使用dynamic标签。 
dynamic元素可以包含多个条件比较元素,并且按照条件比较元素的表述对参数值进行比较,来组装动态SQL。 
这里主要的条件比较元素包含isGreaterThan、isNotNull、isEmpty…… 

dynamic元素和条件比较元素,都是组成动态SQL的一部分,其中的prepend属性根据实际情况的需要辅助的组装动态SQL。 

以上面的statement为例: 
1)dynamic的prepend只要检测到第一个为“真”的条件比较元素,则覆盖其prepend属性并组装where关键字为动态SQL的一部分。 
2)isNotNull的prepend只要检测到参数值满足比较条件,则前置组装and关键字为动态SQL的一部分。 

注意一点:上面的例子中,ibtis文档中说 - dynamic元素中的prepend属性“where”将覆盖第一个为“真”的条件比较元素(即isGreaterThan)的prepend属性 
按照这个理解,则第一个为“真”的条件比较元素(即isGreaterThan)的prepend属性是不需要的,或者“and”是不需要的,(ibatis文档中的原文是 For example, in the case of the first true condition, there is no need for the AND, and in fact it would break the statement) 则修改上述例子为 
Java代码   收藏代码
  1. "someName" parameterClass="Account" resultMap="account-result" >  
  2.   select * from ACCOUNT  
  3.   "where">  
  4.     "id" compareValue="0">  
  5.       ACC_ID = #id#  
  6.       
  7.     "and" property="lastName">  
  8.       ACC_LAST_NAME = #lastName#  
  9.       
  10.     
  11. order by ACC_LAST_NAME  
  12.   

事实上,这样修改的结果导致最终SQL 变为 
“select * from ACCOUNT where ACC_ID = #id#    ACC_LAST_NAME = #lastName#” 
明显是有问题的。 

跟踪源码发现,ibatis在检测sqlTag的时候,调用了如下方法 
Java代码   收藏代码
  1. public void pushRemoveFirstPrependMarker(SqlTag tag) {  
  2.      
  3.    if(tag.getHandler() instanceof DynamicTagHandler) {  
  4.      // this was added to retain default behavior  
  5.      if(tag.isPrependAvailable()) {  
  6.        removeFirstPrependStack.addFirst(  
  7.            new RemoveFirstPrependMarker(tag,true));  
  8.      } else {  
  9.        removeFirstPrependStack.addFirst(  
  10.            new RemoveFirstPrependMarker(tag,false));  
  11.      }  
  12.     ……  

dynamic要覆盖第一个为“真”的条件比较元素的prepend属性,首先需要检测该tag的prepend是否可用(tag.isPrependAvailable()),如果不可用的话,即便该比较条件为“真”,则不会覆盖,只是单独的添加该比较条件元素下的SQL 

Java代码   收藏代码
  1. public boolean isPrependAvailable() {  
  2.   return prependAttr != null && prependAttr.length() > 0;  
  3. }  

由此可以看出,prepend可用的前提是prepend属性值已经设置,并且长度>0。 

这样的话就不难理解上述修改后的statement,为何SQL变更为“select * from ACCOUNT where ACC_ID = #id#    ACC_LAST_NAME = #lastName#”?因为ACC_LAST_NAME = #lastName#的前置prepend,被作为第一个为真的比较条件给删除了。 
正确的写法应该是 
Java代码   收藏代码
  1. "and" property="id" compareValue="0">  

或者 
Java代码   收藏代码
  1. " " property="id" compareValue="0">  

你可能感兴趣的:(mybati(ibatis)中的动态sql 的详解)