开发人员在使用JDBC框架或者其他类似的框架进行数据库开发时,通常都要根据需求去手动拼接SQL,这样非常麻烦,而myBatis提供了对SQL语句动态组装的功能,恰好解决了这一问题。

一,动态SQL中的元素

  动态SQL是MyBatis的强大特性之一,MyBatis 3后采用了基于OGNL的表达式来完成动态SQL,

  MyBatis动态SQL中的主要元素,如下:

元素 说明
<if> 判断语句,用于单条件分支判断
<choose>(<when>,<otherwise>) 相当于Java中的switch..case...default
<where>,<trim>,<set> 补助元素,用于处理一些SQL拼接,特殊字符问题
<foreach> 循环语句,常用于in语句等例举条件中
<bind> 从OGNL表达式中创建一个变量,并将其绑定到上下文中,常用于模糊查询的sql中

二.

1.<if>元素:通常用于通过多个条件来精确查询某个数据

  在MyBatis中,<if>元素是最常用的判断语句,它类似Java中的if语句,主要用于简单的条件判断。

  (1)在映射文件中使用<if>元素来编写根据客户名和客户职业组合信息来查询客户信息.

<!-- 使用if元素来进行查询 -->
<select id="findCustomerByNameAndJobs" parameterType="com.itheima.po.Customer"
resultType="com.itheima.po.Customer">
select * from t_customer where 1=1
<if test="username != null and username !='' ">
and username like concat('%',#{username},'%')
</if>
<if test="jobs != null and jobs !='' ">
and jobs=#{jobs}
</if>
</select>

  使用<if>元素的test属性对username和jobs进行了非空判断(test属性常用于条件判断中,用于判断真假,大部分时候是用于进行非空判断),如果传入的条件非空,就进行sql拼接。

  (2)在测试类中,编写测试方法findCustomerByNameAndJobs:

/**
* 根据用户名和用户的工作来查询用户
*/
@Test
public void findCustomerByNameAndJobsTest() {
//通过工具类来生成SqlSession对象
SqlSession sqlSession=MyBatisUtils.getSession();
//创建Customer对象,封装需要组合查询的条件
Customer customer=new Customer();
customer.setJobs("teacher");
customer.setUsername("jack"); //执行SqlSession对象的查询方法,返回一个结果集
List<Customer> customers=sqlSession.selectList("com.itheima.mapper.CustomerMapper.findCustomerByNameAndJobs", customer);
//输出查询结果
for(Customer customer2:customers) {
System.out.println(customer2);
} //关闭sqlSession
sqlSession.close();
}

  (3)测试结果:

  (4)如果将上面代码中的设值注释掉,如下,就会将所有的信息都输出来:

     /**
* 根据用户名和用户的工作来查询用户
*/
@Test
public void findCustomerByNameAndJobsTest() {
//通过工具类来生成SqlSession对象
SqlSession sqlSession=MyBatisUtils.getSession();
//创建Customer对象,封装需要组合查询的条件
Customer customer=new Customer();
//customer.setJobs("teacher");
//customer.setUsername("jack"); //执行SqlSession对象的查询方法,返回一个结果集
List<Customer> customers=sqlSession.selectList("com.itheima.mapper.CustomerMapper.findCustomerByNameAndJobs", customer);
//输出查询结果
for(Customer customer2:customers) {
System.out.println(customer2);
} //关闭sqlSession
sqlSession.close();
}

 2.<choose>,<when>,<otherwise>:从多个选项中选一个去执行

  在<if>中,只要test属性中的条件为真,就去执行元素中的条件语句,但是有时候在实际生活中是需要从多个选项中选择一个去执行,例如

  当客户名不可空,则只根据客户名进行客户筛选,

  当客户名为空,职业不为空时就根据客户职业进行客户筛选,

  如果两者都为空,就查询出所有电话不为空的客户信息

  在此种情况下,是不能使用<if>元素的,针对如上情况,可以使用<choose>,<when>,<otherwise>元素组合实现上面的情况

  (1).在映射文件中配置如下

<!-- <choose>(<when>,<otherwise>元素的组合使用) -->
<select id="findCustomerByNameOrJobs" parameterType="com.itheima.po.Customer"
resultType="com.itheima.po.Customer">
select * from t_customer where 1=1
<choose> <when test="username != null and username != '' ">
and username like concat('%',#{username},'%')
</when>
<when test="jobs != null and jobs !='' ">
and jobs=#{jobs}
</when>
<otherwise>
and phone is not null
</otherwise> </choose>
</select>

  在上述代码中,使用了<choose>,<when>,<otherwise>组合,当第一个<when>元素中的条件为真时,则只动态地组装第一个<when>元素中的条件,否则就继续向下判断第二个<when>元素中的条件是否为真,依次类推,如果<when>中的条件都不为真时,就会执行<otherwise>内的SQL片段。

  (2)创建测试方法

/**
* 根据用户名或者职业来查询用户信息
*/
@Test
public void findCustomerByNameOrJobs() {
//通过工具类来生成SqlSession对象
SqlSession sqlSession=MyBatisUtils.getSession();
//创建Customer对象,封装需要组合查询的条件
Customer customer=new Customer();
customer.setJobs("teacher");
customer.setUsername("jack"); //执行SqlSession对象的查询方法,返回一个结果集
List<Customer> customers=sqlSession.selectList("com.itheima.mapper.CustomerMapper.findCustomerByNameOrJobs", customer);
//输出查询结果
for(Customer customer2:customers) {
System.out.println(customer2);
} //关闭sqlSession
sqlSession.close();
}

  (3)测试结果

  (4)当把customer.setUsername("jack")注释掉后,结果为:

  (5)如果把customer.setJobs(“teacher”)也注释掉后,结果为:

  

3.<where>,<trim>元素

  在前面的小节中编写的SQL后面都添加了“where 1=1 "这个条件,那么为什么要这么写呢?是应为如果将后面的”where 1=1“去掉,那么MyBatis拼接出来的SQL语句将会出错

  SELECT *from t_customer  where and usename like  concat( '%',#{username}, '%');

  在上面的语句中,where后面跟的是and,这样将出错,而加入了where 1=1 后,既保证了where后面的条件成立,也保证了避免where后面跟着是and或者or.

那么在Mybatis中有什么办法是可以不加入”1=1“这个条件也可以呢?

  MyBatis提供了<where>元素来处理这样的问题。例如

   <select id="findCustomerByNameAndJobs" parameterType="com.itheima.po.Customer"
resultType="com.itheima.po.Customer">
select * from t_customer
     <where>
<if test="username != null and username !='' ">
and username like concat('%',#{username},'%')
</if>
<if test="jobs != null and jobs !='' ">
and jobs=#{jobs}
</if>
    </where>
</select>

  在上面的语句中,使用<where>元素取代了”where 1=1“, where元素会自动判断组合条件下的拼接的sql语句,只有当<where>里的条件成立时,才会在拼接sql时,加入where元素,否则不会添加,即使where后面有多余的"and",“or”,<where>元素会自动将它们除去。

4.<set>元素

  在Hibernate中,如果要更新一条数据,就需要发送所有的字段给持久化对象,然而在实际应用中,大多数情况下,是只跟新某一个字段或者几个字段,如果更新的每一条数据都要将所有的属性都更新一遍,那么其执行效率是非常的低,有没有办法使程序只更新需要更新的字段?

  在MyBatis中,提供了<set>元素来完成这一工作,<set>元素的作用用于更新操作,其主要作用是在动态包含的SQL语句前输出一个SET关键字,并且将SQL语句中最后一个多余的逗号去除。

  例如,在入门案例中,使用<set>元素对更新操作的代码进行修改如下:

<!-- set元素的使用 -->
<update id="updateCustomer" parameterType="com.itheima.po.Customer"> update t_customer
<set>
<if test="username != null and username !='' ">
username=#{username},
</if>
<if test="jobs != null and jobs != ''">
jobs=#{jobs},
</if>
<if test ="phone != null and phone != ''">
phone=#{phone},
</if>
</set>
where id=#{id} </update>

   在上面的sql语句中,使用了<set>和<if>语句相组合的方法将组装update语句,其中<set>元素会自动的动态前置SET关键字,同时也会消除sql语句的最后一个多余的逗号,<if>元素是用来判断相应的字段是否传入值,如果传入的更新字段非空,就将此字段进行动态的组装,并且更新此字段,否则此字段不更新。

  在测试类中编写如下代码:

    /**
*使用set 更新客户
*/
@Test
public void updateCustomer1Test() {
//1.通过工具类来生成SqlSession对象
SqlSession sqlSession=MyBatisUtils.getSession();
//2.创建Customer对象,并向对象中添加数据
Customer customer=new Customer();
customer.setId(3);
customer.setPhone("444444");
//3.执行sqlSession的更新方法,返回的是受影响的行数
int rows=sqlSession.update("com.itheima.mapper.CustomerMapper.updateCustomer", customer);
//4.根据返回的结果来判断是否更新成功
if(rows>0) {
System.out.println("更新成功!");
}else {
System.out.println("更新失败!");
} //5.提交事务
sqlSession.commit();
//6.关闭事务
sqlSession.close();
}

  测试结果如下:

  注意:使用<set>和<if>元素组合进行update语句动态的SQL组装时,如果<set>中的内容都为空,则会出现sql语法错误,所以在<set>元素进行动态更新时,要确保传入的更新字段不为空。

5.<foreach>元素

  该元素是用于数组和集合循环遍历。

  <foreach>元素是通常在构建IN条件语句时使用的,其使用方法如下

<select id="findCustomerByIds" parameterType="List" resultType="com.itheima.po.Customer">
select * from t_customer where id in
<foreach item="id" index="index" collection="list" open="(" separator="," close=")">
#{id}
</foreach>
</select>

  在上述代码中,使用了<foreach>元素对传入的集合进行了遍历并进行了动态的SQL组转,其属性如下:

  item:配置的是循环中当前的元素。

  index:配置的是当前元素在集合的位置下标。

  collection:配置的list是传递过来的参数类型(首字母小写),她可以是一个array,list(或者是collection),Map集合的建,POJO包装类中数组或者集合类型的属性名。

  open和close:配置的是以什么符号将这些集合元素包装起来。

  separate:配置的是各个元素之间的间隔符。

  在测试类中编写如下代码,验证

/**
* 根据客户编号批量查询客户信息
*/
@Test
public void findCustomerByIdsTest() {
//1.获取SqlSession对象
SqlSession sqlSession=MyBatisUtils.getSession();
//2.创建一个list集合,用来封装查询的id值
List<Integer> ids=new ArrayList<Integer>();
ids.add(2);
ids.add(3);
//3.执行SqlSession的查询方法,返回结果集
List<Customer> customers=sqlSession.selectList("com.itheima.mapper.CustomerMapper.findCustomerByIds", ids);
//4.输出查询的结果
for(Customer customer:customers) {
System.out.println(customer);
}
//5.关闭sqlSession
sqlSession.close();
}

  测试结果如下:

  注意:在使用<foreach>元素时,应注意的事项是collection属性值,该属性是必须要指定的,并且在不同的情况下,该属性的值是不同的,主要三种情况:

  (1)如果在调用该sql语句时,传入的是一个参数,并且参数的类型是一个数组或者是list的时候,该collection属性值就是array和list(或者collection)

  (2)如果传入的是多个参数的时候,就需要把它们封装成一个Map,单个参数也是可以这样封装的,这时候collection属性值就是Map的键

  (3)如果传进来的是POJO的包装类的时候,collection属性值就是该包装类中需要进行遍历的数组或者集合的属性名。

MyBatis学习——动态SQL的更多相关文章

  1. Mybatis学习--动态SQL

    学习笔记,选自Mybatis官方中文文档:http://www.mybatis.org/mybatis-3/zh/dynamic-sql.html MyBatis 的强大特性之一便是它的动态 SQL. ...

  2. MyBatis 学习-动态 SQL 篇

    MyBatis 为我们提供了如下几个动态 SQL 元素: if choose foreach where/set trim 一.IF 元素 <select id="selectProj ...

  3. Java-MyBatis:MyBatis 3 动态 SQL

    ylbtech-Java-MyBatis:MyBatis 3 动态 SQL 1.返回顶部 1. 动态 SQL MyBatis 的强大特性之一便是它的动态 SQL.如果你有使用 JDBC 或其它类似框架 ...

  4. MyBatis 构造动态 SQL 语句

    以前看过一个本书叫<深入浅出 MFC >,台湾 C++ 大师写的一本书.在该书中写到这样一句话,“勿在浮沙筑高台”,这句话写的的确对啊.编程很多语言虽然相通,但是真正做还是需要认真的学习, ...

  5. MyBatis的动态SQL详解

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

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

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

  7. mybatis 使用动态SQL

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

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

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

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

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

随机推荐

  1. 控制台连接oracle11g报ORA-12560异常

    oracle11g R2 64bit oracleClient 11.2 32bit PL/SQL Developer 11.0.2 32bit 今天发现了一个奇怪的现象,如图: 后来发现机器上既有s ...

  2. [题解] LuoguP6075 [JSOI2015]子集选取

    传送门 ps: 下面\(n\)和\(k\)好像和题目里的写反了...将就着看吧\(qwq\) 暴力打个表答案就出来了? 先写个结论,答案就是\(2^{nk}\). 为啥呢? 首先你需要知道,因为一个集 ...

  3. Windows 2000 栈溢出 利用异常

    当在一个函数(test)里面自定义了异常处理,如下: 那么在运行时,它会把自定义的异常处理函数MyExceptionhandler()的地址放入栈中(PUSH 004013CC) 然后把fs:[0]的 ...

  4. Angular 后台报错记录

    异常信息:ERROR TypeError: Cannot read property 'xxxx' of undefined 异常原因:"xxx"属性未定义,引发异常的原因可能是H ...

  5. DevOps专题|Lua引擎打造超轻量级客户端

    Lua 作为一门轻量级脚本语言,源码使用标准C语言发布,语法简洁,非常适合嵌入式.客户端.游戏等场景. Lua引擎语言特点 轻量级 源码简单,以lua最新版5.3.5为例,加上lua自身提供的lib库 ...

  6. web网页外部分享到微信、朋友圈、扣扣、微博等功能、自动生成二维码等

    1.这里重中之重是分享到微信:web端网页通常是没有权限分享过去的 所以用: weixin://dl/business/?ticket=ta428dhj739hg3efe6e  但是这个ticket真 ...

  7. C 的printf函数

    头文件 #include <stdio.h> printf函数是最常用的格式化输出函数,原型为:int printf(char *format,......); printf函数会根据参数 ...

  8. MarkDown简易教程+语法

    一.标题 一个#是一级,两个#是二级,最大六级 二.字体 1.加粗 要加粗的文字左右分别用两个*号包起来 2.斜体 要倾斜的文字左右分别用一个*号包起来 3.斜体加粗 要倾斜和加粗的文字左右分别用三个 ...

  9. 解决vue-cli3不停请求 /sockjs-node/info?t= 问题

    使用cli3会遇到一直报错get不到/sockjs-node/info?t= 的问题: 如果你的项目没有用到 sockjs,那么就找到报错的地方,将其注释掉即可. 路径在/node_modules/s ...

  10. JetBrains,vim配置文件, .ideavimrc

    addr: https://github.com/NorseLZJ/lzj-config/tree/master/idea_vim