MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦。例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。
MyBatis 提供了可以被用在任意 SQL 映射语句中的强大的动态 SQL 语言得以改进这种情形。
动态 SQL 元素和 JSTL 或基于类似 XML 的文本处理器相似。在 MyBatis 之前的版本中,有很多元素需要花时间了解。MyBatis 3 大大精简了元素种类,现在只需学习原来一半的元素便可。MyBatis 采用功能强大的基于 OGNL 的表达式来淘汰其它大部分元素。
- if
- choose (when, otherwise)
- trim (where, set)
- foreach
动态 SQL 通常要做的事情是根据条件包含 where 子句的一部分
拼接条件的时候,加了一个恒等条件(1=1),避免多出and
public List getUserBylike(@Param("username") String username,
@Param("state") Integer state);
select * from t_user where 1=1
and username like #{username}
and state like #{state}
List userList = userMapper.getUserBylike("%a%",1);
select * from t_user where 1=1 and username like ? and state like ?
强调一下:
1)在接口中最好加@Param注解,以防止以下异常ReflectionException: There is no getter for property named...
2)if 标签里的 test属性里是用的OGNL表达式,这是apache下的一个标签,用法类似 jstl,但有些小差别,具体的内容可以在ognl官网上查询,有些特殊符号在xml文件里不能直接使用,可以在w3cschool里查http://www.w3school.com.cn/tags/html_ref_entities.html,比如:双引号(< 使用 <)
二、where标签上面恒等条件(1=1),避免多出and ,但是,Mybatis提供了一种解决办法就是 where标签,
where 元素只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入“WHERE”子句。而且,若语句的开头为“AND”或“OR”,where 元素也会将它们去除。
select * from t_user
and username like concat('%',concat(#{username},'%'))
and state like #{state}
List userList = userMapper.getUserBylike("a",1);
select * from t_user WHERE username like concat('%',concat(?,'%')) and state like ?
注意:where标签只能去掉语句的开头为“AND”或“OR” ,并不能去掉后面的,如果我们非要写在后面,这时可以通过自定义 trim 元素来定制 where 元素的功能。
三、 trim 标签(自定义 trim 元素)
四个属性:
prefix:表示在trim包裹的sql语句拼接的前缀
suffix:表示在trim包裹的sql语句拼接的后缀
prefixOverrides:表示去掉(覆盖)trim包裹的SQL的指定首部内容
suffixOverrides:表示去掉(覆盖)trim包裹的SQL的指定尾部内容
如果是先要去掉and或者or,则必须这样写prefixOverrides=“AND |OR”,注意中间的空格。
select * from t_user
username like #{username} and
state like #{state} and
四、set标签
用于动态更新语句的解决方案叫做 set。set 元素可以用于动态包含需要更新的列,而舍去其它的。
public boolean updateUser(User user);
update t_user
username=#{username},
pazzword=#{pazzword},
state=#{state},
reg_date=#{regDate},
where id=#{id}
这里,set 元素会动态前置 SET 关键字,同时也会删掉无关的逗号,因为用了条件语句之后很可能就会在生成的 SQL 语句的后面留下这些逗号。(译者注:因为用的是“if”元素,若最后一个“if”没有匹配上而前面的匹配上,SQL 语句的最后就会有一个逗号遗留)
若你对 set 元素等价的自定义 trim 元素的代码感兴趣,那这就是它的真面目:
update t_user
username=#{username},
pazzword=#{pazzword},
state=#{state},
reg_date=#{regDate},
where id=#{id}
五、choose (when, otherwise)标签
有时我们不想应用到所有的条件语句,而只想从中择其一项。针对这种情况,MyBatis 提供了 choose元素,它有点像 Java 中的 switch...case,从上到下匹配,找到匹配的条件,就结束匹配其他的!
select * from t_user where
username like #{username}
state like #{state}
1=1
六、foreach标签
动态 SQL的另外一个常用的操作需求是对一个集合/数组进行遍历,通常是在构建 IN 条件语句的时候
collection="ids" : 接口上传过来的数值或list集合或者map集合都可以
item="id" :设定遍历集合或数组里的每一个值的迭代变量
separator="," : 因为要构造出 (1,2,3)这种样子的字符串,设定中间的分隔符
open="(" : 因为要构造出 (1,2,3)这种样子的字符串,设定前缀的符号(
close=")": 因为要构造出 (1,2,3)这种样子的字符串,设计结尾的后缀)
index: 了解,数组或list集合的时候,设置索引变量,如果是Map集合就是map的key的迭代变量
//通过一组id值查询对应的user
public List selectUserByIds(@Param("ids") int[] ids);
select * from t_user where id in
#{id}
int[] ids = new int[] {1,2};
List userList = userMapper.selectUserByIds(ids);
System.out.println(Arrays.asList(userList));
----
select * from t_user where id in ( ? , ? )
foreach 元素的功能非常强大, 对于不同数据库之间的批量操作也是经常使用。
七、bind标签(了解)bind 元素可以从 OGNL 表达式中创建一个变量并将其绑定到上下文
上面例子中的模糊查询 传参,使用bind元素 拼接 % 号, 注意不能传null值
select * from t_user where
username like #{new_username}
state like #{state}
1=1
ends ~