1. 概述

  • 动态 SQL 极大的简化了我们拼装SQL的操作;
  • MyBatis 采用功能强大的基于 OGNL 的表达式来简化操作:
    • if
    • choose(when,otherwise)
    • trim(where(封装查询条件), set(封装修改条件))
    • foreach
// EmployeeMapper.java
public interface EmployeeMapper{ // employee 携带了哪个字段,查询条件就带上哪个字段
public List<Employee> getEmpsByConditionIf(Employee employee); // trim
public List<Employee> getEmpsByConditionTrim(Employee employee); //choose
public List<Employee> getEmpsByConditionChoose(Employee employee); // 修改数据库中的值
public void updateEmp(Employee employee); // foreach 查询
public List<Employee> getEmpsByConditionForeach(List<Integer> ids); // foreach 批量添加
public void addEmps(@Param("emps")List<Employee> emps); // bind 标签
public List<Employee> getEmpsTestInnerParameter(Employee employee);
} // EmployeeMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="cn.itcast.mybatis.dao.EmployeeMapper"> <!-- if: 判断
示例一: 查询员工, 要求: employee 中携带了哪个字段,查询条件就带上哪个字段
-->
<select id="getEmpsByConditionIf" resultType="cn.itcast.mybatis.bean.Employee">
select * from tbl_employee
where <!--
test="判断表达式(OGNL)"
如果使用特殊符合,需要写成转义字符:
&&:&amp;&amp;
"":&quot;&quot; 备注:
查询的时候,如果某些条件没带,SQL 拼装可能会出现问题, 例如 id=null
解决方法:
1. 在 where 后面添加 1=1, 以后的条件都 and xxx
2. mybatis 使用 where 标签来将所有的查询条件包括在内;
mybatis 会将 where 标签,拼装的 SQL 语句中多出来的 and 或者 or 去掉;
where 标签只会去掉第一个多出来的 and 或者 or, 不会去掉如下语句中的 and
<if test="id!=null">
id=#{id} and
</if>
...(省略)
-->
<if test="id!=null">
id=#{id}
</if>
<if test="lastName!=null and lastName!=''">
and last_name like #{lastName}
</if>
<if test="email!=null and email.trim()!=''">
and email=#{email}
</if>
<if test="gender==0 or gender==1">
and gender=#{gender}
</if> <!-- SQL 拼装改进方式: 使用 where 标签 -->
<where>
<if test="id!=null">
id=#{id}
</if>
....(同上)
</where>
</select> <!--
trim: 自定义字符串的截取规则
prefix="": 给 trim标签体中SQL拼串后的这个字符串添加一个前缀;
prefixOverrides="": 去掉整个字符串前面多余的字符;
suffix=""
suffixOverrides=""
-->
<select id="getEmpsByConditionTrim" resultType="cn.itcast.mybatis.bean.Employee">
select * from tbl_employee
<trim prefix="where" suffixOverrides="and">
<if test="id!=null">
id=#{id} and
</if>
<if test="lastName!=null and lastName!=''">
last_name like #{lastName} and
</if>
<if test="email!=null and email.trim()!=''">
email=#{email} and
</if>
<if test="gender==0 or gender==1">
gender=#{gender}
</if>
</trim>
</select> <!--
choose: 分支选择
示例二: 如果带了 id, 就使用 id 查询; 如果带了 lastName, 就用 lastName 查询; 只会进入其中一个
-->
<select id="getEmpsByConditionChoose" resultType="cn.itcast.mybatis.bean.Employee">
select * from tbl_employee
<where>
<choose>
<when test="id!=null">
id=#{id}
</when>
<when test="lastName!=null and lastName!=''">
last_name like #{lastName}
</when>
<otherwise>
gender=0
</otherwise>
</choose>
</where>
</select> <!--
set: 封装修改条件
-->
<!-- 第一种方式: 未使用 set 标签之前,可能出现多逗号,导致查询错误 -->
<select id="updateEmp">
update tbl_employee
set
<if test="lastName!=null">
last_name=#{lastName},
</if>
<if test="email!=null">
email=#{email},
</if>
<if test="gender!=null">
gender=#{gender}
</if>
where id=#{id}
</select> <!-- 第二种方式: 使用 set 标签, 可以自动去除多余的逗号 -->
<select id="updateEmp">
update tbl_employee
<set>
<if test="lastName!=null">
last_name=#{lastName},
</if>
<if test="email!=null">
email=#{email},
</if>
<if test="gender!=null">
gender=#{gender}
</if>
</set>
where id=#{id}
</select> <!-- 第三种方式: 使用 trim 标签 -->
<select id="updateEmp">
update tbl_employee
<trim prefix="set" suffixOverrides=",">
<if test="lastName!=null">
last_name=#{lastName},
</if>
<if test="email!=null">
email=#{email},
</if>
<if test="gender!=null">
gender=#{gender}
</if>
</trim>
where id=#{id}
</select> <!--
forEach:
-->
<!-- 使用 forEach 之前 -->
<select id="getEmpsByConditionForeach" resultType="cn.itcast.mybatis.bean.Employee">
select * from tbl_employee where id in(1,2,3)
</select> <!-- 使用 foreach 查询 -->
<select id="getEmpsByConditionForeach" resultType="cn.itcast.mybatis.bean.Employee">
select * from tbl_employee where id in
<!--
collection: 指定要遍历的集合; (具体见"参考资料"中"Parameter...")
list 类型的参数会封装到map中,map的key就叫 list,
数组类型的参数,将会以 "arry" 作为键
item: 将当前遍历出的元素赋值给指定的变量;
#{变量名}: 就能取出变量的值,也就是当前遍历出的元素;
seperator: 每个元素之间的分隔符;
open: 遍历出所有结果,拼接一个开始的字符;
close: 遍历出所有结果,拼接一个结束的字符;
index: 索引,遍历list 的时候,index 就是索引,item就是当前值;
遍历map 的时候,index 表示的就是map的key,item就是map的值;
-->
<foreach collection="list" item="item_id" separator="," open="(" close=")">
#{item_id}
</foreach> <!-- 第二种方式: 在参数中使用注解 @Param("指定名称")
public List<Employee> getEmpsByConditionForeach(@Param("ids")List<Integer> ids);
-->
<foreach collection="ids" item="item_id" seperator="," open="(" close=")">
#{item_id}
</foreach>
</select> <!-- 使用 foreach 批量保存 -->
<!-- 第一种方式 -->
<insert id="addEmps">
insert into tbl_employee(last_name,email,gender,d_id)
values
<foreach collection="emps" item="emp" separator=",">
(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
</foreach>
</insert> <!-- 第二种方式:
需要更改 dbconfig.properties:
jdbc.url=jdbc:mysql://localhost:3306/mybatis?allowMultiQueries=true
-->
<insert id="addEmps">
<foreach collection="emps" item="emp" separator=";">
insert into tbl_employee(last_name,email,gender,d_id)
values(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
</foreach>
</insert> <!-- Oracle 数据库批量保存:
Oracle 不支持values(),(),...
Oracle 支持的批量方式:
1. 多个 insert 放在 begin...end 里面
begin
insert into employees(employee_id,last_name,email)
values(employees_seq.nextval,'test001','test001@163.com');
insert into employees(employee_id,last_name,email)
values(employees_seq.nextval,'test002','test002@163.com');
end;
2. 利用中间表
insert into employees(employee_id,last_name,email)
select employees_sql.nextval,lastName,email from(
select 'test_a_01' lastName,'test_a_e01' email from dual
union
select 'test_a_02' lastName,'test_a_e02' email from dual
union
select 'test_a_03' lastName,'test_a_e03' email from dual
)
-->
<!-- Oracle 批量添加第一种方式 -->
<insert id="addEmps" databaseId="oracle">
<foreach collection="emps" item="emp" open="begin" close="end;">
insert into employees(employee_id,last_name,email)
values(employees_seq.nextval,#{emp.lastName},#{emp.email});
</foreach>
</insert> <!-- Oracle 批量添加第二种方式 -->
<insert id="addEmps" databaseId="oracle">
insert into employees(employee_id,last_name,email)
select employees_sql.nextval,lastName,email from(
<foreach collection="emps" item="emp" separator="union">
select #{emp.lastName} lastName,#{emp.email} email from dual
</foreach>
)
</insert> <!-- 两个内置参数:
不只是方法传递过来的参数可以被用来判断,取值,
mybatis 默认还有两个内置参数:
_parameter:代表整个参数
单个参数: _parameter 就是这个参数;
多个参数: 参数会被封装成一个map, _parameter 就是代表这个map; _databaseId: 如果 mybatis-config.xml 中配置了 databaseIdProvider 标签,
_databaseId 就是当前数据库的别名;
--> <!-- bind 标签: 可以将OGNL表达式的值绑定到一个变量中,方便后来引用这个变量的值 -->
<select id="getEmpsTestInnerParameter" resutlType="cn.itcast.mybatis.bean.Employee"> <bind name="_lastName" value="'%'+lastName+'%'"/> <if test="_databaseId='mysql'">
select * from tbl_employee
<if test="_parameter!=null">
where last_name like #{_lastName}
</if>
</if>
<if ttest="_databaseId='oracle'">
select * from employees
<if test="_parameter!=null">
where last_name like #{_lastName}
</if>
</if>
</select> <!-- sql 标签: 抽取可重用的sql片段,方便后面引用
1. sql抽取: 经常将要查询的列名,或者插入用的列名抽取处理方便引用;
2. include 来引用已经抽取的sql;
3. include 还可以自定义一些property, sql 标签内部就能使用自定义的属性: ${property}
-->
<sql id="insertColumn">
last_name,email,gender,d_id
</sql> <!-- 修改上面foreach 批量保存(mysql) -->
<insert id="addEmps">
insert into tbl_employee(
<!-- include 标签: 引用外部定义的sql -->
<include refid="insertColumn"></include>
)
values
<foreach collection="emps" item="emp" separator=",">
(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
</foreach>
</insert>
</mapper> // 测试类
public class MyBatisTest{ @Test
public void testDynamicSql() throws IOException{
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); SqlSession openSession = sqlSessionFactory.openSession(); try{
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
// 创建查询条件
Employee emp = new Employee(1,"%e%",null,null); // 测试 if 查询
List<Employee> list = mapper.getEmpsByConditionIf(emp); // 测试 trim 查询
List<Employee> list = mapper.getEmpsByConditionTrim(emp); System.out.println(list); // 测试 set
Employee emp = new Employee(3,"lisi",null,null);
mapper.updateEmp(emp);
openSession.commit(); // 测试 foreach 查询
List<Employee> list = mapper.getEmpsByConditionForeach(Arrays.asList(1,2,3,4));
for(Employee empl : list){
System.out.println(empl);
} // 测试 foreach 批量保存
List<Employee> list = new ArrayList<>();
list.add(new Employee(null,"lisi","lisi@163.com","1",new Department(1)));
list.add(new Employee(null,"mike","mike@163.com","0",new Department(2)));
mpper.addEmps(emps);
openSession.commit(); }finally{
openSession.close();
}
}
}
1.1 <if> 查询

1.2 <where> 查询, 后面多出 and

1.3 <set> 标签使用之前,查询语句中多出逗号

参考资料

MyBatis 之动态SQL的更多相关文章

  1. MyBatis的动态SQL详解

    MyBatis的动态SQL是基于OGNL表达式的,它可以帮助我们方便的在SQL语句中实现某些逻辑,本文详解mybatis的动态sql,需要的朋友可以参考下 MyBatis 的一个强大的特性之一通常是它 ...

  2. Mybatis解析动态sql原理分析

    前言 废话不多说,直接进入文章. 我们在使用mybatis的时候,会在xml中编写sql语句. 比如这段动态sql代码: <update id="update" parame ...

  3. mybatis 使用动态SQL

    RoleMapper.java public interface RoleMapper { public void add(Role role); public void update(Role ro ...

  4. MyBatis框架——动态SQL、缓存机制、逆向工程

    MyBatis框架--动态SQL.缓存机制.逆向工程 一.Dynamic SQL 为什么需要动态SQL?有时候需要根据实际传入的参数来动态的拼接SQL语句.最常用的就是:where和if标签 1.参考 ...

  5. 使用Mybatis实现动态SQL(一)

    使用Mybatis实现动态SQL 作者 : Stanley 罗昊 [转载请注明出处和署名,谢谢!] 写在前面:        *本章节适合有Mybatis基础者观看* 前置讲解 我现在写一个查询全部的 ...

  6. MyBatis探究-----动态SQL详解

    1.if标签 接口中方法:public List<Employee> getEmpsByEmpProperties(Employee employee); XML中:where 1=1必不 ...

  7. mybatis中的.xml文件总结——mybatis的动态sql

    resultMap resultType可以指定pojo将查询结果映射为pojo,但需要pojo的属性名和sql查询的列名一致方可映射成功. 如果sql查询字段名和pojo的属性名不一致,可以通过re ...

  8. mybatis.5.动态SQL

    1.动态SQL,解决关联sql字符串的问题,mybatis的动态sql基于OGNL表达式 if语句,在DeptMapper.xml增加如下语句; <select id="selectB ...

  9. MyBatis的动态SQL详解-各种标签使用

    MyBatis的动态SQL是基于OGNL表达式的,它可以帮助我们方便的在SQL语句中实现某些逻辑. MyBatis中用于实现动态SQL的元素主要有: if choose(when,otherwise) ...

  10. 利用MyBatis的动态SQL特性抽象统一SQL查询接口

    1. SQL查询的统一抽象 MyBatis制动动态SQL的构造,利用动态SQL和自定义的参数Bean抽象,可以将绝大部分SQL查询抽象为一个统一接口,查询参数使用一个自定义bean继承Map,使用映射 ...

随机推荐

  1. 180508 - 解决有关VIVO的2018-04-01安全补丁导致的APP闪退问题

    解决有关VIVO的2018-04-01安全补丁导致的APP闪退问题 [√]问题原因猜测4: 最终解决方案 [√]问题原因猜测3: 尝试解决 [√成功] [×]问题原因猜测2: 尝试解决 [×失败] [ ...

  2. Application Architecture Determines Application Performance

     Application Architecture Determines Application Performance Randy Stafford AppliCATion ARCHiTECTuR ...

  3. (WPF)依赖属性

    属性触发器: <Button MinWidth=" 75" Margin="10"> <Button.Style> <Style ...

  4. 算法提高 道路和航路 SPFA 算法

    我简单的描述一下题目,题目中所说的有道路和航路: 1.公路是双向的,航路是单向的: 2.公路是正值,航路可正可负: 每一条公路i或者航路i表示成连接城镇Ai(1<=A_i<=T)和Bi(1 ...

  5. JVM Specification 9th Edition (4) Chapter 3. Compiling for the Java Virtual Machine

    Chapter 3. Compiling for the Java Virtual Machine 内容列表 3.1. Format of Examples 3.2. Use of Constants ...

  6. 通过PDO 连接SQL Server

    下载PDO_DBLIB库 PDO的各种库都可以在PECL中找到,例如,MySQL库:PDO_MYSQL.Oracle库:PDO_OCI. 作为SQL Server 的连接库,通过下面命令下载PDO_D ...

  7. android viewpager嵌套使用photoview异常问题

    最近,做项目时,遇到一个需求,需要像淘宝评论那样,一组图点开,然后可以双指滑动放大,并左右切换换图的功能.自然就想到了使用viewpager+photoview来实现这一功能,但是在实现后,却发现一个 ...

  8. NIPS(Conference and Workshop on Neural Information Processing Systems)

    论文提交时间:5月下旬 会议时间:12月上旬 NIPS2017: 网址:https://nips.cc/

  9. 长尾分布,重尾分布(Heavy-tailed Distribution)

    Zipf分布: Zipf分布是一种符合长尾的分布: 就是指尾巴很长的分布.那么尾巴很长很厚的分布有什么特殊的呢?有两方面:一方面,这种分布会使得你的采样不准,估值不准,因为尾部占了很大部分.另一方面, ...

  10. redhat ent6.5使用centos yum

    转载自:http://blog.csdn.net/zhngjan/article/details/20843465 搜狐镜像库:mirrors.sohu.com 163镜像库:mirrors.163. ...