编译软件:IntelliJ IDEA 2019.2.4 x64
操作系统:win10 x64 位 家庭版
Maven版本:apache-maven-3.6.3
Mybatis版本:3.5.6
文章目录
- 一. 在sql映射文件中如何写注释?
- 二. 什么是动态sql?
- 三. 动态sql常用标签有哪些?
- 3.1 if标签
- 3.2 where标签
- 3.3 trim标签
- 3.4 set标签
- 3.5 choose标签
- 3.6 foreach标签
- 3.7 sql标签
一. 在sql映射文件中如何写注释?
关于XXXMapper接口对应的映射文件里SQL中的注释
👉语法
①方式一
//mysql的注释
-- 1=1
②方式二
//xml的注释
<!-- 1=1 -->
❓使用这两种注释方式各有什么不同呢?
👉请看如下测试
代码示例如下:
①使用第一种注释
<!-- 根据查询条件查找对应的员工信息(条件不确定) 即采用动态的sql去查询 -->
<select id="selectEmpByopr" resultType="employee">
SELECT
`id`,
`last_name`,
`email`,
`salary`,
`dept_id`
FROM
`tbl_employee`
WHERE
-- 1=1
<if test="id !=null">
and id=#{id}
</if>
<if test="lastName != null">
and last_name=#{lastName}
</if>
<if test="email != null">
and email=#{email}
</if>
<if test="salary != null">
and last_name=#{salary}
</if>
</select>
②使用第二种注释
<!-- 根据查询条件查找对应的员工信息(条件不确定) 即采用动态的sql去查询 -->
<select id="selectEmpByopr" resultType="employee">
SELECT
`id`,
`last_name`,
`email`,
`salary`,
`dept_id`
FROM
`tbl_employee`
WHERE
<!-- 1=1-->
<if test="id !=null">
and id=#{id}
</if>
<if test="lastName != null">
and last_name=#{lastName}
</if>
<if test="email != null">
and email=#{email}
</if>
<if test="salary != null">
and last_name=#{salary}
</if>
</select>
💡结论
通过以上二者运行测试结果对比,所以在需要使用注释时,推荐使用第二种注释方式
二. 什么是动态sql?
👉定义
- 动态sql指的是sql语句可动态化
- Mybatis的动态sql中支持OGNL表达式语言,OGNL(Object Graph Navigation
Language)是对象图导航语言
❗注意
👉用法案例
不指定查询条件,查询对应员工信息,即当你传入id,程序就根据id去查,传入什么条件,就去根据此条件去查(多个条件不确定)
代码示例如下
①在EmployeeMapper接口下书写相应的方法
//动态的sql方式,即不指定查询条件,查询对应员工信息
public List<Employee> selectEmpByopr(Employee employee);
②在EmployeeMapper接口相应的sql
<!-- 根据查询条件查找对应的员工信息(条件不确定) 即采用动态的sql去查询 -->
<select id="selectEmpByopr" resultType="employee">
SELECT
`id`,
`last_name`,
`email`,
`salary`,
`dept_id`
FROM
`tbl_employee`
WHERE
<if test="id !=null">
and id=#{id}
</if>
<if test="lastName != null">
and last_name=#{lastName}
</if>
<if test="email != null">
and email=#{email}
</if>
<if test="salary != null">
and last_name=#{salary}
</if>
</select>
③测试
@Test
public void test01(){
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//通过SqlSessionFactory对象调用openSession();
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取EmployeeMapper的代理对象
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
//动态参数(无参会报错,没有第一个参数也会报错)
Employee employee=new Employee();
List<Employee> employees = employeeMapper.selectEmpByopr(employee);
//遍历集合employees
for (Employee employee1 : employees) {
System.out.println(employee1);
}
} catch (IOException e) {
e.printStackTrace();
}
}
❓但是这样会出现一个问题,即不传参会报错,没有第一个参数也会报错
💡原因分析
不传参时,mybatis解析sql的过程中走到where的部分,无参,会进入where里,但不会执行里面的任意if判断,where后没有任何赋值表达式,此sql为非法sql,故报错。没有第一个参数时也会报类似的问题。
👉解决方案
①在第二步中的where里加上 1=1,作为条件恒等式(老版本的解决措施)
②使用where标签
代码示例如下:
<!-- 根据查询条件查找对应的员工信息(条件不确定) 即采用动态的sql去查询 -->
<select id="selectEmpByopr" resultType="employee">
SELECT
`id`,
`last_name`,
`email`,
`salary`,
`dept_id`
FROM
`tbl_employee`
<where>
<if test="id !=null">
and id=#{id}
</if>
<if test="lastName != null">
and last_name=#{lastName}
</if>
<if test="email != null">
and email=#{email}
</if>
<if test="salary != null">
and last_name=#{salary}
</if>
</where>
</select>
三. 动态sql常用标签有哪些?
3.1 if标签
👉功能
用于完成简单的判断
示例代码如下:
//如果属性id不为空,就将传入的参数id赋值给sql中的字段id
<if test="id !=null">
id=#{id}
</if>
3.2 where标签
👉功能:
用于解决where关键字及where后第一个and或or的问题
示例代码如下:
<where>
<if test="id !=null">
and id=#{id}
</if>
<if test="lastName != null">
and last_name=#{lastName}
</if>
<if test="email != null">
and email=#{email}
</if>
<if test="salary != null">
and last_name=#{salary}
</if>
</where>
3.3 trim标签
👉功能
可以在条件判断完的SQL语句前后添加或者去掉指定的字符
👉属性
prefix
:添加前缀prefixOverrides
:去掉前缀suffix
:添加后缀suffixOverrides
:去掉后缀
👉用法案例
不指定查询条件,查询对应员工信息(trim标签优化版)
代码示例如下:
①在EmployeeMapper接口定义相应的方法
//不指定查询条件,查询对应员工信息
public List<Employee> selectEmpByEmpTrim(Employee employee);
②在EmployeeMapper接口对应的映射文件中定义相应的sql
<!-- 根据查询条件查找对应的员工信息(条件不确定) 动态的sql(trim标签优化版) -->
<select id="selectEmpByEmpTrim" resultType="employee">
SELECT
`id`,
`last_name`,
`email`,
`salary`,
`dept_id`
FROM
`tbl_employee`
<!-- 给下面的sql语句加上前缀 where,去掉后缀and -->
<trim prefix="where" suffixOverrides="and">
<if test="id !=null">
id=#{id} and
</if>
<if test="lastName != null">
last_name=#{lastName} and
</if>
<if test="email != null">
email=#{email} and
</if>
<if test="salary != null">
salary=#{salary} and
</if>
</trim>
</select>
③测试
@Test
public void test02(){
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//通过SqlSessionFactory对象调用openSession();
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取EmployeeMapper的代理对象
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
//动态参数
Employee employee=new Employee();
/* employee.setLastName("jack");
employee.setSalary(5600.0);
*/
List<Employee> employees = employeeMapper.selectEmpByEmpTrim(employee);
//遍历集合employees
for (Employee employee1 : employees) {
System.out.println(employee1);
}
} catch (IOException e) {
e.printStackTrace();
}
}
trim标签运行流程详解
3.4 set标签
👉功能
主要用于解决set关键字及多出一个【,】问题
👉用法案例
修改员工的信息
代码示例如下:
①在EmployeeMapper接口中定义修改员工的信息的方法
//修改员工的信息
public void updateEmp(Employee employee);
②在EmployeeMapper接口对应的映射文件中书写相应的sql
问题版(会出现多一个【,】问题
)
<update id="updateEmp">
update
tbl_employee
set
<if test="lastName != null">
last_name=#{lastName} ,
</if>
<if test="email != null">
email=#{email} ,
</if>
<if test="salary != null">
salary=#{salary} ,
</if>
where
id=#{id}
</update>
set标签解决问题版
<update id="updateEmp">
update
tbl_employee
<set>
<if test="lastName != null">
last_name=#{lastName} ,
</if>
<if test="email != null">
email=#{email} ,
</if>
<if test="salary != null">
salary=#{salary} ,
</if>
</set>
where
id=#{id}
</update>
③测试
@Test
public void test03(){
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//通过SqlSessionFactory对象调用openSession();
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取EmployeeMapper的代理对象
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
//动态参数
Employee employee=new Employee();
employee.setId(1);
employee.setLastName("tom");
employee.setSalary(16800.0);
employeeMapper.updateEmp(employee);
xml
} catch (IOException e) {
e.printStackTrace();
}
}
使用问题版的sql进行测试
使用set标签解决问题版的sql进行测试
3.5 choose标签
👉功能
类似java中if-else【switch-case】结构
👉应用场景
应用于单个条件不确定的业务场景
👉用法案例
不指定查询条件,查询对应的员工信息(单个条件不确定的)
代码示例如下:
①在EmployeeMapper接口书写相应的方法
//不指定查询条件,查询对应员工信息(单个条件不确定的)
public List<Employee> selectEmpByOneOpr(int empId);
②在EmployeeMapper接口对应的映射文件中书写相应的sql
<!-- 根据查询条件查找对应的员工信息(条件不确定) 动态的sql(trim标签优化版) -->
<select id="selectEmpByOneOpr" resultType="employee">
SELECT
`id`,
`last_name`,
`email`,
`salary`,
`dept_id`
FROM
`tbl_employee`
<where>
<choose>
<when test="id !=null">
id=#{id}
</when>
<when test="lastName != null">
last_name=#{lastName}
</when>
<when test="email != null">
email=#{email}
</when>
<otherwise>
salary=#{salary}
</otherwise>
</choose>
</where>
</select>
③测试
@Test
public void test04(){
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//通过SqlSessionFactory对象调用openSession();
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取EmployeeMapper的代理对象
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
List<Employee> employees = employeeMapper.selectEmpByOneOpr(1);
System.out.println(employees);
} catch (IOException e) {
e.printStackTrace();
}
}
3.6 foreach标签
👉功能
类似java中for循环
👉标签属性
collection
:要迭代的集合item
:当前从集合中迭代出的元素separator
:元素与元素之间的分隔符open
:开始字符close
:结束字符
👉应用场景
🚩 ①遍历迭代
用法案例
通过多个id获取员工的信息 【EmpIds:员工id的集合】
代码示例如下:
a.在EmployeeMapper接口定义相应的方法
/**
* 通过多个id获取员工的信息 【EmpIds:员工id的集合】
* @param EmpIds
* @return
*/
public List<Employee> selectEmpByIds(@Param("ids") List<Integer> EmpIds);
b.在EmployeeMapper接口对应的映射文件中定义相应的sql
<select id="selectEmpByIds" resultType="employee">
SELECT
`id`,
`last_name`,
`email`,
`salary`,
`dept_id`
FROM
`tbl_employee`
<where>
`id` in
(
<foreach collection="ids" item="id" separator=",">
#{id}
</foreach>
)
</where>
</select>
c.测试
@Test
public void test04(){
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//通过SqlSessionFactory对象调用openSession();
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取EmployeeMapper的代理对象
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
List<Employee> employees = employeeMapper.selectEmpByOneOpr(1);
System.out.println(employees);
} catch (IOException e) {
e.printStackTrace();
}
}
🚩②批量导入
用法案例
批量添加员工数据
代码示例如下:
a.在EmployeeMapper接口定义相应的方法
//批量添加员工数据
public void batchInsertEmp(@Param("emps") List<Employee> employees);
b.在EmployeeMapper接口对应的映射文件中定义相应的sql
// 批量添加员工数据,使用insert标签书写相应的sql
<insert id="batchInsertEmp">
insert into
tbl_employee(last_name,email,salary)
values
<foreach collection="emps" item="emp" separator=",">
(#{emp.lastName},#{emp.email},#{emp.salary})
</foreach>
</insert>
c.测试
@Test
public void test06(){
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//通过SqlSessionFactory对象调用openSession();
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取EmployeeMapper的代理对象
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
//定义要添加的员工集合
List<Employee> list=new ArrayList<>();
list.add(new Employee("zhangsan","sdhjsd@qq.com",6700.0));
list.add(new Employee("wangwu","dddhjsd@123.com",9700.0));
employeeMapper.batchInsertEmp(list);
sqlSession.commit();
} catch (IOException e) {
e.printStackTrace();
}
}
3.7 sql标签
👉功能
提取可重用SQL片段
❗注意
该SQL片段可以是一个完整的sql语句,也可以是一个sql语句中的某个片段)
👉用法案例
使用sql标签对3.6小节中的应用场景1的案例里映射文件里的的”select xxx,xxxx,xxx from
xxxx”部分提取出来,作为一个可重用的sql片段,在select>标签内引入该sql片段
代码示例如下:
①使用sql标签抽取映射文件中”select xxx,xxxx,xxx from xxxx”部分片段作为可重用的sql片段
<!-- 抽取映射文件中”select xxx,xxxx,xxx from xxxx”部分片段作为可重用的sql片段 -->
<sql id="select_employee">
SELECT
`id`,
`last_name`,
`email`,
`salary`,
`dept_id`
FROM
`tbl_employee`
</sql>
<select id="selectEmpByIds" resultType="employee">
<!-- 将刚才抽取的sql片段select_employee引入进来 -->
<include refid="select_employee"></include>
<where>
`id` in
(
<foreach collection="ids" item="id" separator=",">
#{id}
</foreach>
)
</where>
</select>
②测试运行