其实MyBatis具有的一个强大的特性之一通常是它的动态 SQL 能力。 如果你有使用 JDBC 或其他 相似框架的经验,你就明白要动态的串联 SQL 字符串在一起是十分纠结的,确保不能忘了空格或在列表的最后省略逗号。Mybatis中的动态 SQL 可以彻底处理这种痛苦。对于动态SQL,最通俗简单的方法就是我们自己在硬编码的时候赋予各种动态行为的判断,而在Mybatis中,用一种强大的动态 SQL 语 言来改进这种情形,这种语言可以被用在任意映射的 SQL 语句中。动态 SQL 元素和使用 JSTL 或其他相似的基于 XML 的文本处理器相似。MyBatis 采用功能强大的基于 OGNL 的表达式来消除其他元素。
我们常用的几个节点元素有if,choose(when, otherwise),trim(where, if),foreach。真正使用下来我感觉有点像XSLT(文章后面会顺带提一下~)的用法。
(1)if 的用法
在ViisitMapper的分页配置中,如果pageIndex>-1 and pageSize>-1的时候就加入相应的分页SQL,否则就不添加(默认取全部),如下:
select * from ( ) t limit #{pageStart}, #{pageSize} select * from Visitor where status>0 order by ${orderFieldStr} ${orderDirectionStr}
因为我们的参数pageIndex与pageSize都是int值所以可以这样直接判断,如果是对象实例我们可以利用null判断来进行一些动态逻辑的控制,具体实际开发中就要看业务需求了。这里我认为要注意的是别十分顺手的吧and写成&&,这个在配置中不会被识别~。
(2)choose (when, otherwise)的用法
choose when 主要在多个条件的情况下只满足其中一个条件的应用场景中使用,例如这里就构建一个query条件,分别传递id,name与createTime。假设我们查询Visitor表时,如果VisitorId有值则,使用Id查询,如果VisitorName有值则采用VisitName查询,如下,还是在david.mybatis.demo.IVisitorOperation接口类中添加List
package david.mybatis.demo;
import java.util.List;
import david.mybatis.model.BasicQueryArgs;
import david.mybatis.model.PagenateArgs;
import david.mybatis.model.Visitor;
import david.mybatis.model.VisitorWithRn;
public interface IVisitorOperation {
public int add(Visitor visitor);
public int delete(int id);
public int update(Visitor visitor);
public Visitor query(int id);
public List getList();
public List getListByPagenate(PagenateArgs args);
public List getListByPagenateWithRn(PagenateArgs args);
public Visitor basicQuery(int id);
public List getListChooseWhenDemo(BasicQueryArgs args);
public List getListWhereDemo(BasicQueryArgs args);
public List getListForeachDemo(List ids);
}
select * from Visitor status=#{queryStatus} and id=#{queryId} and name like #{queryName} and createTime>= #{queryTime}
(3)where if (trim)的用法
where关键词的好处是在于,如果有相应的过滤条件的话,它知道在适当的时候插入where关键词。而且它也知道在何时该去掉相应的AND与OR的连接符,主要应对如下情景
不会因为所有条件不满足变为
或者因为没有满足第一个条件,单单满足后面的条件变成
所以针对这种我们可以在建立choose when条件示例,同样在IVisitorOperation接口类中加入相应的方法public List
select * from Visitor status>0 and id=#{queryId} and name like=#{queryName} and createTime>=#{queryTime}
(4)foreach的用法
在常用的动态SQL中我们有个业务场景是要where id in 一大串的ID,像这种情况我们就可以用到foreach啦,不必自己辛辛苦苦去拼接Id字符串啦。同样的步骤还是在IVisitorOperation接口类中加入相应的方法public List
select * from Visitor
最后你只需要在DemoRun中建立相应的测试方法,Mybatis里面的动态SQL也就完成啦,下面测试用的DemoRun方法
public static void getListForeachDemo(Listids) { SqlSession session = MybatisUtils.getSqlSession(); IVisitorOperation vOperation = session.getMapper(IVisitorOperation.class); List ls = vOperation.getListForeachDemo(ids); for (Visitor visitor : ls) { System.out.println(visitor); } } public static void getListWhereCondition(int id, String name, Date createTime) { name = name == "" ? null : name; SqlSession session = MybatisUtils.getSqlSession(); BasicQueryArgs args = new BasicQueryArgs(id, name, createTime); IVisitorOperation vOperation = session.getMapper(IVisitorOperation.class); List ls = vOperation.getListWhereDemo(args); if (ls.size() == 0) System.out.println("查无匹配!"); else { for (Visitor visitor : ls) { System.out.println(visitor); } } } public static void getListChooseWhenDemo(int id, String name, Date createTime) { name = name == "" ? null : name; SqlSession session = MybatisUtils.getSqlSession(); BasicQueryArgs args = new BasicQueryArgs(id, name, createTime); IVisitorOperation vOperation = session.getMapper(IVisitorOperation.class); List ls = vOperation.getListChooseWhenDemo(args); if (ls.size() == 0) System.out.println("查无匹配!"); else { for (Visitor visitor : ls) { System.out.println(visitor); } } }
PS:关于OGNL
OGNL 是 Object-Graph Navigation Language 的缩写,从语言角度来说:它是一个功能强大的表达式语言,用来获取和设置 java 对象的属性 , 它旨在提供一个更高抽象度语法来对 java 对象图进行导航,OGNL 在许多的地方都有应用,例如:
作为 GUI 元素(textfield,combobox, 等)到模型对象的绑定语言。
数据库表到 Swing 的 TableModel 的数据源语言。
web 组件和后台 Model 对象的绑定语言 (WebOGNL,Tapestry,WebWork,WebObjects) 。
作为 Jakarata Commons BeanUtils 或者 JSTL 的表达式语言的一个更具表达力的替代语言。
另外,java 中很多可以做的事情,也可以使用 OGNL 来完成,例如:列表映射和选择。 对于开发者来说,使用 OGNL,可以用简洁的语法来完成对 java 对象的导航。通常来说: 通过一个“路径”来完成对象信息的导航,这个“路径”可以是到 java bean 的某个属性,或者集合中的某个索引的对象,等等,而不是直接使用 get 或者 set 方法来完成。



