在开发中,经常会遇到要执行的 SQL 语句其实并不是固定,而是随条件的变化而变化的。对于这种情况 MyBatis 也有解决方案。
随条件变化的 SQL
先看一个固定的 SQL 语句,查询指定 name 和 age 的人:
<resultMap id="PersonMap" type="Person">
<id column="id" jdbcType="INTEGER" property="pid" javaType="int"/>
<result column="name" jdbcType="VARCHAR" property="pname" javaType="String"/>
<result column="age" jdbcType="INTEGER" property="page" javaType="int"/>
</resultMap>
<select id="selectWithNothing" parameterType="Person" resultMap="PersonMap">
SELECT id, name, age
FROM person
WHERE name = #{name} and age = #{age}
</select>
上面的 SQL 当 name 或 age 为空时,该查询将会抛出异常。
if 标签
在不确定查询条件是否为空时,可以用 if 标签进行检查:
<select id="selectWithIf" parameterType="Person" resultMap="PersonMap">
select id, name, age
from person
where 1=1
<if test="pname != null and pname != '' ">
and name = #{pname}
</if>
<if test="page != null and page != 0 ">
and age < #{page}
</if>
</select>
注意:where 后的 1 = 1 建议加上,这样可以避免无一条件满足时,最终的 SQL 语句中 where 后面没有过滤条件。
调用方法如下:
public void selectWithIf(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
Person entity = new Person();
entity.setPname("Jimmy");
List<Person> persons = sqlSession.selectList("edu.wzm.mybatis.mapping.PersonMapper.selectWithIf", entity);
System.out.println(persons);
sqlSession.close();
}
where - if 标签
在 SELECT 语句中,为了简化 if 标签,可以使用 where - if 标签组合使用:
<select id="selectWithIfWhere" parameterType="Person" resultMap="PersonMap">
selectid, name, age
from person
<where>
<if test="pname != null and pname != '' ">
and name = #{pname}
</if>
<if test="page != null and page != 0 ">
and age < #{page}
</if>
</where>
</select>
在 where - if 标签中,SQL 语句可以加上 and,MyBatis 会自动识别。
调用方法:
public void selectWithIfWhere(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
Person entity = new Person();
entity.setPname("Jimmy");
entity.setPage(30);
List<Person> persons = sqlSession.selectList("edu.wzm.mybatis.mapping.PersonMapper.selectWithIfWhere", entity);
System.out.println(persons);
sqlSession.close();
}
set - if 标签
在 UPDATE 语句中,为了简化 if 标签,可以使用 set - if 标签组合使用:
<update id="updateWithIfSet" parameterType="Person">
updateperson
<set>
<if test="pname != null and pname != '' ">
name = #{pname}
</if>
<if test="page != null and page != 0 ">
and age = #{page}
</if>
</set>
where id = #{pid}
</update>
set 标签为自动为每个 if 标签中的 SQL 语句加上逗号隔开。
调用方法:
public void updateWithIfSet(){
SqlSession sqlSession = MyBatisUtils.getSqlSession(true);
Person entity = new Person();
entity.setPid(2);
entity.setPname("Bill");
int result = sqlSession.update("edu.wzm.mybatis.mapping.PersonMapper.updateWithIfSet", entity);
System.out.println(result);
sqlSession.close();
}
trim - if 标签
还有一种更强大的组合标签 trim - if,它既可以处理 SELECT语句,又可以处理 UPDATE 语句。如代替上面的 where - if 标签:
<select id="selectWithIfTrim" parameterType="Person" resultMap="PersonMap">
SELECT id,name, age
FROM person
<trim prefix="WHERE" prefixOverrides="AND|OR">
<if test="pname != null and pname != '' ">
name = #{pname}
</if>
<if test="page != null and page != 0 ">
age < #{page}
</if>
</trim>
</select>
代替上面的 set - if 标签:
<update id="updateWithIfTrim" parameterType="Person">
UPDATE person
<trim prefix="SET" prefixOverrides=",">
<if test="pname != null and pname != '' ">
name = #{pname}
</if>
<if test="page != null and page != 0 ">
age < #{page}
</if>
</trim>
WHERE id = #{pid}
</update>
choose - when 标签
上面的标签都是一组条件的中的每一个条件要么可选,要么不选。但是对于一组互斥的条件,只能从中选择一个,那么上面的标签就不好处理了,需要使用 choose - when 标签:
<select id="selectWithChooseWhen" parameterType="Person" resultMap="PersonMap">
SELECT id, name, age
FROM person
<where>
<choose>
<when test="pname != null and pname != '' ">
name = #{pname}
</when>
<when test="page != null and page != 0 ">
AND age < #{page}
</when>
<otherwise>
</otherwise>
</choose>
</where>
</select>
注意:choose - when 标签类似于 if - elseif - else。
循环
对于动态 SQL 非常必须的,主是要迭代一个集合,通常是用于 IN 条件。List 实例将使用 “list” 做为键,数组实例以 “array” 做为键。
foreach 元素是非常强大的,它允许你指定一个集合,声明集合项和索引变量,它们可以用在元素体内。它也允许你指定开放和关闭的字符串,在迭代之间放置分隔符。这个元素是很智能的,它不会偶然地附加多余的分隔符。
注意:可以传递一个List实例或者数组作为参数对象传给是MyBatis。当你这么做的时候,MyBatis 会自动将它包装在一个 Map中,用名称在作为键。List 实例将会以 “list” 作为键,而数组实例将会以 “array” 作为键。
数组
使用数组实例作为参数:
<select id="selectWithForeachArray" resultMap="PersonMap">
SELECT id, name, age
FROM person
WHERE id IN
<foreach collection="array" item="pid" open="(" separator="," close=")">
#{pid}
</foreach>
</select>
调用方法:
public void selectWithForeachArray(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
int[] pids = {1, 3};
List<Person> persons = sqlSession.selectList("edu.wzm.mybatis.mapping.PersonMapper.selectWithForeachArray", pids);
System.out.println(persons);
sqlSession.close();
}
列表
使用列表作为参数:
<select id="selectWithForeachList" resultMap="PersonMap">
SELECT id, name, age
FROM person
WHERE id IN
<foreach collection="list" item="pid" open="(" separator="," close=")">
#{pid}
</foreach>
</select>
调用方法:
public void selectWithForeachList(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
List<Integer> pids = new ArrayList<>();
pids.add(2);
pids.add(3);
List<Person> persons = sqlSession.selectList("edu.wzm.mybatis.mapping.PersonMapper.selectWithForeachList", pids);
System.out.println(persons);
sqlSession.close();
}