在页面原型中,列表上方的条件是动态的,是可以不传递的,也可以只传递其中的1个或者2个或者全部。
而在我们刚才编写的SQL语句中,我们会看到,我们将三个条件直接写死了。 如果页面只传递了参数姓名name 字段,其他两个字段 性别 和 入职时间没有传递,那么这两个参数的值就是null。
此时,执行的SQL语句为:
这个查询结果是不正确的。正确的做法应该是:传递了参数,再组装这个查询条件;如果没有传递参数,就不应该组装这个查询条件。
比如:如果姓名输入了"张", 对应的SQL为:
select * ?from emp where name like '%张%' order by update_time desc;
如果姓名输入了"张",,性别选择了"男",则对应的SQL为:
select * ?from emp where name like '%张%' and gender = 1 order by update_time desc;
SQL语句会随着用户的输入或外部条件的变化而变化,我们称为:动态SQL。
在Mybatis中提供了很多实现动态SQL的标签,我们学习Mybatis中的动态SQL就是掌握这些动态SQL标签。
<if>
:用于判断条件是否成立。使用test属性进行条件判断,如果条件为true,则拼接SQL。
<if test="条件表达式">
? 要拼接的sql语句
</if>
接下来,我们就通过<if>
标签来改造之前条件查询的案例。
示例:把SQL语句改造为动态SQL方式
原有的SQL语句
<select id="list" resultType="com.itheima.pojo.Emp">
? ? ? select * from emp
? ? ? where name like concat('%',#{name},'%')
? ? ? ? ? ? and gender = #{gender}
? ? ? ? ? ? and entrydate between #{begin} and #{end}
? ? ? order by update_time desc
</select>
动态SQL语句
<select id="list" resultType="com.itheima.pojo.Emp">
? ? ? select * from emp
? ? ? where
? ?
? ? ? ? ? ? <if test="name != null">
? ? ? ? ? ? ? ? name like concat('%',#{name},'%')
? ? ? ? ? ? </if>
? ? ? ? ? ? <if test="gender != null">
? ? ? ? ? ? ? ? and gender = #{gender}
? ? ? ? ? ? </if>
? ? ? ? ? ? <if test="begin != null and end != null">
? ? ? ? ? ? ? ? and entrydate between #{begin} and #{end}
? ? ? ? ? ? </if>
? ?
? ? ? order by update_time desc
</select>
测试方法:
@Test
public void testList(){
? ?//性别数据为null、开始时间和结束时间也为null
? ?List<Emp> list = empMapper.list("张", null, null, null);
? ?for(Emp emp : list){
? ? ? ?System.out.println(emp);
? }
}
执行的SQL语句:
下面呢,我们修改测试方法中的代码,再次进行测试,观察执行情况:
@Test
public void testList(){
? ?//姓名为null
? ?List<Emp> list = empMapper.list(null, (short)1, null, null);
? ?for(Emp emp : list){
? ? ? ?System.out.println(emp);
? }
}
执行结果:
再次修改测试方法中的代码,再次进行测试:
@Test
public void testList(){
? ?//传递的数据全部为null
? ?List<Emp> list = empMapper.list(null, null, null, null);
? ?for(Emp emp : list){
? ? ? ?System.out.println(emp);
? }
}
执行的SQL语句:
以上问题的解决方案:使用<where>
标签代替SQL语句中的where关键字
<where>
只会在子元素有内容的情况下才插入where子句,而且会自动去除子句的开头的AND或OR
<select id="list" resultType="com.itheima.pojo.Emp">
? ? ? select * from emp
? ? ? ?<where>
? ? ? ? ? ? <!-- if做为where标签的子元素 -->
? ? ? ? ? ? <if test="name != null">
? ? ? ? ? ? ? ? and name like concat('%',#{name},'%')
? ? ? ? ? ? </if>
? ? ? ? ? ? <if test="gender != null">
? ? ? ? ? ? ? ? and gender = #{gender}
? ? ? ? ? ? </if>
? ? ? ? ? ? <if test="begin != null and end != null">
? ? ? ? ? ? ? ? and entrydate between #{begin} and #{end}
? ? ? ? ? ? </if>
? ? ? ?</where>
? ? ? order by update_time desc
</select>
测试方法:
@Test
public void testList(){
? ?//只有性别
? ?List<Emp> list = empMapper.list(null, (short)1, null, null);
? ?for(Emp emp : list){
? ? ? ?System.out.println(emp);
? }
}
执行的SQL语句:
案例:完善更新员工功能,修改为动态更新员工数据信息
动态更新员工信息,如果更新时传递有值,则更新;如果更新时没有传递值,则不更新
解决方案:动态SQL
修改Mapper接口:
@Mapper
public interface EmpMapper {
? ?//删除@Update注解编写的SQL语句
? ?//update操作的SQL语句编写在Mapper映射文件中
? ?public void update(Emp emp);
}
修改Mapper映射文件:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
? ? ? ?PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
? ? ? ?"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.EmpMapper">
?
? ?<!--更新操作-->
? ?<update id="update">
? ? ? update emp
? ? ? set
? ? ? ? ? ?<if test="username != null">
? ? ? ? ? ? ? username=#{username},
? ? ? ? ? ?</if>
? ? ? ? ? ?<if test="name != null">
? ? ? ? ? ? ? name=#{name},
? ? ? ? ? ?</if>
? ? ? ? ? ?<if test="gender != null">
? ? ? ? ? ? ? gender=#{gender},
? ? ? ? ? ?</if>
? ? ? ? ? ?<if test="image != null">
? ? ? ? ? ? ? image=#{image},
? ? ? ? ? ?</if>
? ? ? ? ? ?<if test="job != null">
? ? ? ? ? ? ? job=#{job},
? ? ? ? ? ?</if>
? ? ? ? ? ?<if test="entrydate != null">
? ? ? ? ? ? ? entrydate=#{entrydate},
? ? ? ? ? ?</if>
? ? ? ? ? ?<if test="deptId != null">
? ? ? ? ? ? ? dept_id=#{deptId},
? ? ? ? ? ?</if>
? ? ? ? ? ?<if test="updateTime != null">
? ? ? ? ? ? ? update_time=#{updateTime}
? ? ? ? ? ?</if>
? ? ? where id=#{id}
? ?</update>
?
</mapper>
测试方法:
@Test
public void testUpdate2(){
? ? ? ?//要修改的员工信息
? ? ? ?Emp emp = new Emp();
? ? ? ?emp.setId(20);
? ? ? ?emp.setUsername("Tom111");
? ? ? ?emp.setName("汤姆111");
?
? ? ? ?emp.setUpdateTime(LocalDateTime.now());
?
? ? ? ?//调用方法,修改员工数据
? ? ? ?empMapper.update(emp);
}
执行的SQL语句:
再次修改测试方法,观察SQL语句执行情况:
@Test
public void testUpdate2(){
? ? ? ?//要修改的员工信息
? ? ? ?Emp emp = new Emp();
? ? ? ?emp.setId(20);
? ? ? ?emp.setUsername("Tom222");
? ? ?
? ? ? ?//调用方法,修改员工数据
? ? ? ?empMapper.update(emp);
}
执行的SQL语句:
以上问题的解决方案:使用<set>
标签代替SQL语句中的set关键字
<set>
:动态的在SQL语句中插入set关键字,并会删掉额外的逗号。(用于update语句中)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
? ? ? ?PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
? ? ? ?"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.EmpMapper">
?
? ?<!--更新操作-->
? ?<update id="update">
? ? ? update emp
? ? ? ?<!-- 使用set标签,代替update语句中的set关键字 -->
? ? ? ?<set>
? ? ? ? ? ?<if test="username != null">
? ? ? ? ? ? ? username=#{username},
? ? ? ? ? ?</if>
? ? ? ? ? ?<if test="name != null">
? ? ? ? ? ? ? name=#{name},
? ? ? ? ? ?</if>
? ? ? ? ? ?<if test="gender != null">
? ? ? ? ? ? ? gender=#{gender},
? ? ? ? ? ?</if>
? ? ? ? ? ?<if test="image != null">
? ? ? ? ? ? ? image=#{image},
? ? ? ? ? ?</if>
? ? ? ? ? ?<if test="job != null">
? ? ? ? ? ? ? job=#{job},
? ? ? ? ? ?</if>
? ? ? ? ? ?<if test="entrydate != null">
? ? ? ? ? ? ? entrydate=#{entrydate},
? ? ? ? ? ?</if>
? ? ? ? ? ?<if test="deptId != null">
? ? ? ? ? ? ? dept_id=#{deptId},
? ? ? ? ? ?</if>
? ? ? ? ? ?<if test="updateTime != null">
? ? ? ? ? ? ? update_time=#{updateTime}
? ? ? ? ? ?</if>
? ? ? ?</set>
? ? ? where id=#{id}
? ?</update>
</mapper>
再次执行测试方法,执行的SQL语句:
小结
<if>
用于判断条件是否成立,如果条件为true,则拼接SQL
形式:
<if test="name != null"> … </if>
<where>
where元素只会在子元素有内容的情况下才插入where子句,而且会自动去除子句的开头的AND或OR
<set>
动态地在行首插入 SET 关键字,并会删掉额外的逗号。(用在update语句中)