MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦。例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。
虽然在以前使用动态 SQL 并非一件易事,但正是 MyBatis 提供了可以被用在任意 SQL 映射语句中的强大的动态 SQL 语言得以改进这种情形。
动态 SQL 元素和 JSTL 或基于类似 XML 的文本处理器相似。在 MyBatis 之前的版本中,有很多元素需要花时间了解。MyBatis 3 大大精简了元素种类,现在只需学习原来一半的元素便可。MyBatis 采用功能强大的基于 OGNL 的表达式来淘汰其它大部分元素。
- if
- choose (when, otherwise)
- trim (where, set)
- foreach
示例
1.动态SQL:if+where语句
where元素只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入“WHERE”子句。而且,若语句的开头为“AND”或“OR”,where 元素也会将它们去除。
示例,在实体类的映射文件中:
注意此处:我用的参数类型是hashMap
userMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mybatisstudy.dao.IUserDao">
<select id="selectUserByUsernameAndSex" parameterType="hashmap"
resultType="com.mybatisstudy.model.User">
SELECT * FROM user
<!-- where 元素只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入“WHERE”子句。而且,若语句的开头为“AND”或“OR”,where
元素也会将它们去除。 -->
<where>
<if test="name!=null">
name=#{name}
</if>
<if test="sex!=null">
and sex=#{sex}
</if>
</where>
</select>
</mapper>
对应的实体类接口中:
public interface IUserDao {
public List<User> selectUserByUsernameAndSex(HashMap<String,Object> argMap);
}
在单元测试类中:
两个参数都输入(在至少有一个子元素的条件返回 SQL 子句的情况时,会添加where)时,
此时的sql语句相当于:select * from user where name='小明' and sex='男';
只输入后一个参数(此时因为只有后一个参数,所以sex前面的and会被自动去掉),
此时的sql语句相当于:select * from user where sex='男';(若不用<where></where>则sql语句会变成select * from user and sex='男'; 这时便会报错)
2.动态SQL:set和if语句
userMapper.xml
<update id="updateUserById" parameterType="com.mybatisstudy.model.User">
update user
<set>
<if test="name!=null and name!=''">
<!-- 注意后面需要有逗号 -->
name=#{name},
</if>
<if test="sex!=null and sex!=''">
<!-- 注意最后一个不需要添加逗号 -->
age=#{age}
</if>
</set>
where id=#{id}
</update>
IUserDao.java(接口)
public int updateUserById(User user);
单元测试类
@Test
public void testSetAndIf() {
User user = new User();
user.setId(1001);
user.setName("大明");
user.setSex("男");
user.setAge(21);
int line = userDao.updateUserById(user);
Assert.assertEquals(line, 1);
}
测试结果
3.动态SQL:choose(when,otherwise) 语句
示例:
userMapper.xml
<select id="selectUserByChoose" parameterType="hashmap" resultType="com.mybatisstudy.model.User">
SELECT * FROm user
<where>
<choose>
<when test="id!=null and id!=''">
id=#{id}
</when>
<when test="name!=null and name!=''">
and name=#{name}
</when>
<otherwise>
and sex=#{sex}
</otherwise>
</choose>
</where>
</select>
IUserDao.java(接口)
public List<User> selectUserByChoose(HashMap<String,Object> argMap);
单元测试类
@Test
public void testChooseAndWhen() {
HashMap<String,Object> argMap = new HashMap<String,Object>();
//argMap.put("id", 1001);
//argMap.put("name", "小明");
argMap.put("sex","男");
List<User> users = userDao.selectUserByUsernameAndSex(argMap);
for(User user : users) {
System.out.println(user);
}
}
测试结果
4.动态SQL:trim元素
trim标记是一个格式化的标记,可以完成set或者是where标记的功能
<trim prefix="WHERE" prefixOverrides="AND |OR "> ... </trim>
prefixOverrides 属性会忽略通过管道分隔的文本序列(注意此例中的空格也是必要的)。它的作用是移除所有指定在 prefixOverrides 属性中的内容,并且插入 prefix 属性中指定的内容。
(1)用 trim 改写上面的 if+where 语句
<!-- 此处我用的参数类型为hashmap,也可以用实体类型 -->
<select id="selectUserByUsernameAndSex" parameterType="hashmap"
resultType="com.mybatisstudy.model.User">
SELECT * FROM user
<!-- where 元素只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入“WHERE”子句。而且,若语句的开头为“AND”或“OR”,where
元素也会将它们去除。 -->
<!-- <where>
<if test="name!=null">
name=#{name}
</if>
<if test="sex!=null">
and sex=#{sex}
</if>
</where> -->
<trim prefix="where" prefixOverrides="and | or">
<if test="name!=null">
name=#{name}
</if>
<if test="sex!=null">
and sex=#{sex}
</if>
</trim>
</select>
(2)用 trim 改写上面的 if+set 语句
<update id="updateUserById"
parameterType="com.mybatisstudy.model.User">
update user
<!-- <set>
<if test="name!=null and name!=''">
name=#{name},
</if>
<if test="sex!=null and sex!=''">
age=#{age}
</if>
</set> -->
<trim prefix="set" suffixOverrides=",">
<if test="name!=null and name!=''">
name=#{name},
</if>
<if test="sex!=null and sex!=''">
age=#{age}
</if>
</trim>
where id=#{id}
</update>
5.动态SQL:foreach的使用
userMapper.xml
根据所给的id集合查找user,也可以用于批量删除等
<select id="selectUserByListId" parameterType="hashmap" resultType="com.mybatisstudy.model.User">
SELECT * FROM user
<where>
<!-- 此处要注意保持必要的空格,如此处and和C之间的空格 -->
<foreach collection="ids" item="id" open="and (" separator="or" close=")">
id=#{id}
</foreach>
</where>
</select>