在页面原型中,条件查询员工信息这个需求来说,列表上方的条件是动态的,是可以不传递的{如果不传递/指定,就代表没有限制条件,查询全部的员工信息},也可以只传递其中的1个或者2个或者全部。
而在我们刚才编写的SQL语句中,我们会看到,我们将三个条件直接写死了。 如果页面只传递了参数姓名name 字段,其他两个字段 性别 和 入职时间没有传递,那么这两个参数的值就是null。
此时,执行的SQL语句为:
package com.gch;
import com.gch.mapper.EmpMapper;
@SpringBootTest
class SpringbootMybatisCrudApplicationTests {
/**
从Spring的IOC容器当中,获取类型是EmpMapper的对象并注入
*/
@Autowired
private EmpMapper empMapper;
/**
条件查询
*/
@Test
public void testSelectList(){
/**
调用查询方法查询员工信息,并将查询返回的结果使用List集合接收封装
*/
List list = empMapper.select("张", null,null,null);
// 遍历集合输出
list.stream().forEach(s ->{
System.out.println(s);
});
}
}
运行测试类: SqlSession
这个查询结果是不正确的。
正确的做法应该是:传递了参数,再组装这个查询条件;如果没有传递参数,就不应该组装这个查询条件。 --- 所以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标签。
Mybatis动态SQL标签:
、
要拼接的sql语句
接下来,我们就通过
标签来改造之前条件查询的案例。
示例:把SQL语句改造为动态SQL方式
原有的SQL语句
动态SQL语句
测试方法:
/**
条件查询
*/
@Test
public void testSelectList(){
/**
调用查询方法查询员工信息,并将查询返回的结果使用List集合接收封装
*/
List list = empMapper.select("张", null,null,null);
// 遍历集合输出
list.stream().forEach(s ->{
System.out.println(s);
});
}
执行的SQL语句以及查询返回的结果:
下面呢,我们修改测试方法中的代码,将参数name改为null,再次进行测试,观察执行情况:
/**
条件查询
*/
@Test
public void testSelectList(){
/**
调用查询方法查询员工信息,并将查询返回的结果使用List集合接收封装
*/
List list = empMapper.select(null, (short)1,null,null);
// 遍历集合输出
list.stream().forEach(s ->{
System.out.println(s);
});
}
执行结果:
注意:框架遇到的错,一定要从下往上看!拉到最后一行,找到最后一个Casued by
Caused by: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax;
原因检查:
再次修改测试方法中的代码,将传递的数据全部改为null,再次进行测试:
/**
条件查询
*/
@Test
public void testSelectList(){
/**
调用查询方法查询员工信息,并将查询返回的结果使用List集合接收封装
*/
List list = empMapper.select(null, null,null,null);
// 遍历集合输出
list.stream().forEach(s ->{
System.out.println(s);
});
}
运行测试方法后:
执行的SQL语句:
标签代替SQL语句中的where关键字 使用
标签只会在子元素有内容的情况下才插入where子句{ 标签它会根据里面的这些子标签动态的来判断里面的条件,如果里面所有的条件都不成立,它就不会生成where关键字;如果里面有一个条件成立,它就会生成where关键字 }而且
标签会自动去除子句的开头的AND或OR
加上
测试方法:
/**
条件查询
*/
@Test
public void testSelectList(){
/**
调用查询方法查询员工信息,并将查询返回的结果使用List集合接收封装
*/
List list = empMapper.select(null, null,null,null);
// 遍历集合输出
list.stream().forEach(s ->{
System.out.println(s);
});
}
案例:完善更新员工功能,将更新员工的功能修改为动态更新员工数据信息
之前的更新操作所存在的问题:
需求:
动态更新员工信息,如果更新时有传递值,则更新该字段;如果更新时没有传递值,则不更新该字段
解决方案:动态SQL
修改Mapper接口中的接口方法:
package com.gch.mapper;
import com.gch.pojo.Emp;
import org.apache.ibatis.annotations.*;
import java.time.LocalDate;
import java.util.List;
/**
加上@Mapper注解就代表程序在运行时会自动的创建该接口的代理对象,并且会将这个代理对象放入到IOC容器当中
*/
@Mapper
public interface EmpMapper {
/**
* 动态更新员工信息
* 删除@Update注解所编写的SQL语句
* 将update操作的SQL语句编写在Mapper映射文件中
* @param emp => 将传递的多个参数封装到实体类对象当中
*/
public void update(Emp emp);
}
修改Mapper映射文件:
update mybatis.emp
set
username = #{username},
name = #{name},
gender = #{gender},
image = #{image},
job = #{job},
entrydate = #{entrydate},
dept_id = #{deptId},
update_time = #{updateTime}
where id = #{id}
测试方法:
c @Test
public void testUpdate2(){
// 构建Emp员工对象
Emp emp = new Emp();
// 要修改的员工信息
emp.setId(5);
emp.setDeptId(2);
// 调用方法,修改员工数据
empMapper.update(emp);
}
运行后的报错以及执行的SQL语句:
以上问题的解决方案:使用
update mybatis.emp
username = #{username},
name = #{name},
gender = #{gender},
image = #{image},
job = #{job},
entrydate = #{entrydate},
dept_id = #{deptId},
update_time = #{updateTime}
where id = #{id}
再次执行测试方法,执行的SQL语句:
用于判断条件是否成立,如果条件为true,则拼接SQL
形式:
…
where元素只会在子元素有内容的情况下才插入where子句,而且会自动去除子句的开头的AND或OR
动态地在行首插入 SET 关键字,并会删掉额外的逗号。(用在update语句中)
update mybatis.emp
username = #{username},
name = #{name},
gender = #{gender},
image = #{image},
job = #{job},
entrydate = #{entrydate},
dept_id = #{deptId},
update_time = #{updateTime}
where id = #{id}
案例:员工删除功能(既支持删除单条记录,又支持批量删除)
SQL语句:
-- 批量删除ID为18,19,20
delete from emp where id in(18,19,20);
Mapper接口:
package com.gch.mapper;
import com.gch.pojo.Emp;
/**
加上@Mapper注解就代表程序在运行时会自动的创建该接口的代理对象,并且会将这个代理对象放入到IOC容器当中
*/
@Mapper
public interface EmpMapper {
/**
* 批量删除员工操作
* 由于是批量删除,一般会使用数组或者集合来封装多个ID值
* @param ids => 批量删除数据的多个ID值,封装到List集合
*/
public void deleteByIds(List ids);
}
XML映射文件:
使用
delete
from mybatis.emp
where id in
#{id}
测试方法:
package com.gch;
import com.gch.mapper.EmpMapper;
@SpringBootTest
class SpringbootMybatisCrudApplicationTests {
/**
从Spring的IOC容器当中,获取类型是EmpMapper的对象并注入
*/
@Autowired
private EmpMapper empMapper;
@Test
public void testDelete(){
// 通过Arrays工具类构造List集合,并使用List集合封装批量删除数据的ID值
List listIds = Arrays.asList(18,19,20);
// 调用方法,批量删除员工操作
empMapper.deleteByIds(listIds);
}
}
执行的SQL语句:
问题分析:
在xml映射文件中配置的SQL,有时可能会存在很多重复的片段,此时就会存在很多冗余的代码
SQL片段: 抽取重复的代码
select id,username,password,name,gender,image,job,entrydate,dept_id,create_time,update_time
from mybatis.emp
然后通过