1.引言
上一篇文章我们实现了MyBatis的多条件查询,然而这样程序还是不够完美,因为设置了多条件查询后我们就必须按照所有的要求进行输入,如:name,age,一旦我们只输入了name,而没有输入age,程序就会报错,所以正确的处理方式应该是我们输入了name,就查询name,如果没有输入name就不判断name的内容,age也是一样,本章使用动态SQL来解决这个问题。
2.<if>标签
使用if标签实现以上的问题,编写mapper代码如下:
<select id="selectStudentByConditionIf" resultType="com.mybatis.beans.Student">
select id,name,age,score
from student
where
<if test="name != null and name != ''">
name like '%' #{name} '%'
</if>
<if test="age > 0 ">
and age > #{age}
</if>
</select>
但是这样写还是会出问题,因为当第一个if不满足而第二个if满足时,则会出现以下SQL语句
select id,name,age,score from student where and age > ?
此时因为第一个if标签不满足,所以就会出现where后面直接接and的语法错误,接着改进mapper代码:
<select id="selectStudentByConditionIf" resultType="com.mybatis.beans.Student">
select id,name,age,score
from student
where 1=1
<if test="name != null and name != ''">
and name like '%' #{name} '%'
</if>
<if test="age > 0 ">
and age > #{age}
</if>
</select>
在where先添加一个1=1就能解决这个问题,后面不管是哪个条件满足都不会让SQL出错,但是代码还是不够好,因为1=1 ,就意味着所有的记录都会做一个判断,当数据量很大时对数据库的负担太大,所以我们需要继续改进代码。
3.<where>标签、<trim>标签、<set>标签
前面使用if标签后可以实现对应的功能,但是代码还是有问题,所以引进where标签进行进一步改进;
<select id="selectStudentByConditionWhere" resultType="com.mybatis.beans.Student">
select id,name,age,score
from student
<where>
<if test="name != null and name != ''">
and name like '%' #{name} '%'
</if>
<if test="age > 0 ">
and age > #{age}
</if>
</where>
</select>
添加where标签后,MyBatis在拼接时会自动删除掉多余的and 或者or关键字。
但是需要注意的是,where只会删除多余的and,不会补充缺失的and,所以在编写的时候在if中都要加上and;
除了where外,还有两个标签有同样的功能,分别是<set>标签和<trim>标签,set标签适用于update操作中删除掉多余的“,”,而trim标签则是where标签和set标签的结合体;
set标签可以将多余的逗号删除掉
<update id="updateStudentByConditonSet" parameterType="Student">
update student
<set>
<if test="name != null and name != ''">
name = #{name},
</if>
<if test="age > 0">
age = #{age},
</if>
<if test="score > 0">
score = #{score},
</if>
</set>
where id = #{id}
</update>
trim标签的作用就相当于where标签和set标签的整合,它既可以删除多余的“and” 、“or”关键字,也可以删除多余的逗号;trim标签在使用的时候需要指定where还是set;
<select id="selectStudentByConditionTrim" resultType="com.mybatis.beans.Student">
select id,name,age,score
from student
<!--设置前缀是where标签,并且删除前面多余的and-->
<trim prefix="WHERE" prefixOverrides="and || or">
<if test="name != null and name != ''">
and name like '%' #{name} '%'
</if>
<if test="age > 0 ">
and age > #{age}
</if>
</trim>
</select>
<update id="updateStudentByConditonTrim" parameterType="Student">
update student
<!--设置前缀是set,后缀式where id = #{id},并且删除后缀多余的逗号-->
<trim prefix="set" suffixOverrides="," suffix="where id = #{id}">
<if test="name != null and name != ''">
name = #{name},
</if>
<if test="age > 0">
age = #{age},
</if>
<if test="score > 0">
score = #{score},
</if>
</trim>
</update>
4.<choose>标签
choose标签的用法和JSTL里的一样,其作用相当于switch,其内部有两个标签<when>和<otherwise>,一个choose中可以有多个when标签,但是只能有一个otherwise标签。
例,要求实现以下功能:如果输入的name不为空就按名称搜索,如果name为空就按年龄查询,如果两个都为空时就不返回任何记录;
<select id="selectStudentByConditionChoose" resultType="com.mybatis.beans.Student">
select id,name,age,score
from student
<where>
<choose>
<when test="name != null and name != ''">
and name like '%' #{name} '%'
</when>
<when test="age > 0">
and age > #{age}
</when>
<otherwise>
and 1=2
</otherwise>
</choose>
</where>
</select>
5.<foreach>标签
在MyBatis中支持使用foreach对传入的参数列表或者数组进行遍历;但是需要注意其collection关键字;
常见使用场景:通过多个id获取数据,批量插入数据等;
| 传入参数类型 | collection关键字 |
|---|---|
| List | list |
| Array | array |
| Map(将以上两种数据手动封装到map中) | map中对应数据的key |
<select id="selectStudentByConditionForeachList" resultType="com.mybatis.beans.Student">
select id,name,age,score
from student
where id in
<foreach collection="list" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
<select id="selectStudentByConditionForeachArray" resultType="com.mybatis.beans.Student">
select id,name,age,score
from student
where id in
<foreach collection="array" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
<select id="selectStudentByConditionForeachMap" resultType="com.mybatis.beans.Student">
select id,name,age,score
from student
where id in
<!--这里使用的myList就是我们将一个List<T>数据封装到map中的key-->
<foreach collection="myList" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
Map<String , Object> map = new HashMap<String , Object>();
List<Integer> ids = new ArrayList<Integer>();
ids.add(1);
ids.add(20);
ids.add(21);
//将一个List封装到map中,在MyBatis中的collection属性就为当前ids的key:myList
map.put("myList", ids);
6.<sql>标签
sql标签适用于所有的SQL语句,其作用是执行字符串的替换,与include标签配套使用;
<sql id="columns">
id , name , age , score
</sql>
<select id="selectStudentByConditionIf" resultType="com.mybatis.beans.Student">
select <include refid="columns"/>
from student
where 1=1
<if test="name != null and name != ''">
and name like '%' #{name} '%'
</if>
<if test="age > 0 ">
and age > #{age}
</if>
</select>