从01开始 从01开始
首页
  • 计算机科学导论
  • 数字电路
  • 计算机组成原理

    • 计算机组成原理-北大网课
  • 操作系统
  • Linux
  • Docker
  • 计算机网络
  • 计算机常识
  • Git
  • JavaSE
  • Java高级
  • JavaEE

    • Ant
    • Maven
    • Log4j
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • Servlet
  • Spring
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC
  • SpringBoot
  • 学习网课的心得
  • 输入法
  • 节假日TodoList
  • 其他
  • 关于本站
  • 网站日记
  • 友人帐
  • 如何搭建一个博客
GitHub (opens new window)

peterjxl

人生如逆旅,我亦是行人
首页
  • 计算机科学导论
  • 数字电路
  • 计算机组成原理

    • 计算机组成原理-北大网课
  • 操作系统
  • Linux
  • Docker
  • 计算机网络
  • 计算机常识
  • Git
  • JavaSE
  • Java高级
  • JavaEE

    • Ant
    • Maven
    • Log4j
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • Servlet
  • Spring
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC
  • SpringBoot
  • 学习网课的心得
  • 输入法
  • 节假日TodoList
  • 其他
  • 关于本站
  • 网站日记
  • 友人帐
  • 如何搭建一个博客
GitHub (opens new window)
  • JavaSE

  • JavaSenior

  • JavaEE

  • JavaWeb

  • Spring

  • 主流框架

    • Redis

    • Mybatis

      • Mybatis介绍
      • Mybatis入门案例
      • Mybatis入门案例-注解
      • Mybatis入门案例-实现类
      • Mybatis内部执行原理概述
      • 实现一个微型的Mybatis-配置文件版
      • 实现一个微型的Mybatis-注解版
      • Mybatis实现CRUD
      • Mybatis中传递对象参数
      • Mybatis中的列名和属性名的映射
      • Mybatis实现DAO层的开发
      • Mybatis实现类的执行过程-查询方法
      • properties标签的使用及细节
      • typeAliases标签和package标签
      • Mybatis连接池和事务
      • Mybatis与JNDI
      • Mybatis中的动态SQL
        • 什么是动态SQL
        • 实践if
        • 多个if
        • where标签
        • foreach标签
        • sql标签
        • 源码
      • Mybatis多表查询
      • Mybatis中的多对多查询
      • Mybatis的延迟加载
      • Mybatis的缓存
      • Mybatis的注解开发-CRUD
      • Mybatis的注解开发-多表查询
      • Mybatis
    • Lucene

    • Elasticsearch

    • MQ

    • MyCat

    • Lombok

    • 主流框架
  • SpringMVC

  • SpringBoot

  • Java并发

  • Java源码

  • JVM

  • 韩顺平

  • Java
  • Java
  • 主流框架
  • Mybatis
2023-04-25
目录

Mybatis中的动态SQL

# 150.Mybatis中的动态SQL

Mybatis 的映射文件中,前面我们的 SQL 都是比较简单的,有些时候业务逻辑复杂时,我们的 SQL 是动态变化的,此时在前面的学习中我们的 SQL 就不能满足要求了。   ‍

# 什么是动态SQL

‍

MyBatis 官网说明 | 动态 SQL (opens new window):动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。

使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。

如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。

‍

举个例子,我们查询的时候,可以允许用户选择多个条件进行查询,也可以不选。例如某购物网站上可以根据订单类型、成交时间等条件,查询订单的数据:

​​

‍

那么在查询的时候,有些参数是有值的,有些又是没有的。此时我们就可以用到动态SQL,它提供了很多标签,例如 <if>​,当有参数则传入,没有则不传入。

‍

‍

# 实践if

我们在IUserDao.java,接口里加一个方法:

List<User> findUserByCondition(User user);
1

user 作为查询的条件,该对象里有可能有用户名,有可能有性别,有可能有地址,有可能都有,也可能都没有

‍

燃煤我们在IUserDao.xml里,配置我们的SQL了:

<!-- 根据可有可无的多个参数进行查询-->
<select id="findUserByCondition"  resultType="USER" resultMap="userMap">
    select * from user where 1=1
    <if test="userName != null">
       and username = #{userName}
    </if>
</select>
1
2
3
4
5
6
7

‍

注意 if 标签里,不能写 && 符号,这是Java语言提供的运算符;而我们现在是写SQL,SQL里有 and 这个关键字,但是没有&&。

此外,test属性里的内容,以及#{}​里的内容,是Java代码里的内容,因此区分大小写,得和User类中的userName成员变量对应起来。

我们写个测试方法:

@Test
public void testFindUserByCondition(){
    User user = new User();
    user.setUserName("王五");

    List<User> users = userDao.findUserByCondition(user);
    for(User u : users){
        System.out.println(u);
    }
}
1
2
3
4
5
6
7
8
9
10

‍

运行结果:

Preparing: select * from user where 1=1 and username = ?
 - ==> Parameters: 王五(String)
 - <==      Total: 1
User{userId=43, userName='王五', userBirthday=Sun Mar 04 11:34:34 CST 2018, userSex='女', userAddress='北京'}
1
2
3
4

‍

# 多个if

也可以使用多个条件:

<!-- 根据可有可无的多个参数进行查询-->
<select id="findUserByCondition"  resultType="USER" resultMap="userMap">
    select * from user where 1=1
    <if test="userName != null">
       and username = #{userName}
    </if>
    <if test="userSex != null">
        and sex = #{userSex}
    </if>
</select>
1
2
3
4
5
6
7
8
9
10

‍

此时我们先不修改测试类,试下运行:

Preparing: select * from user where 1=1 and username = ?
 - ==> Parameters: 王五(String)
 - <==      Total: 1
User{userId=43, userName='王五', userBirthday=Sun Mar 04 11:34:34 CST 2018, userSex='女', userAddress='北京'}
1
2
3
4

由于我们的userSex是null,因此查询的SQL里也不会有该条件

‍

‍

而如果我们设置了性别:

@Test
public void testFindUserByCondition(){
    User user = new User();
    user.setUserName("王五");
    user.setUserSex("女");
    List<User> users = userDao.findUserByCondition(user);
    for(User u : users){
        System.out.println(u);
    }
}
1
2
3
4
5
6
7
8
9
10

‍

那么运行结果里,就可以看到,SQL里也加上了性别:

- ==>  Preparing: select * from user where 1=1 and username = ? and sex = ?
- ==> Parameters: 王五(String), 女(String)
- <==      Total: 1
User{userId=43, userName='王五', userBirthday=Sun Mar 04 11:34:34 CST 2018, userSex='女', userAddress='北京'}
1
2
3
4

‍

# where标签

刚刚我们使用了where 1 =1 的条件,看起来不够简洁明了;而如果使用where标签,可以更简化配置:

<select id="findUserByCondition"  resultType="USER" resultMap="userMap">
    select * from user
    <where>
        <if test="userName != null">
            and username = #{userName}
        </if>
        <if test="userSex != null">
            and sex = #{userSex}
        </if>
    </where>
</select>
1
2
3
4
5
6
7
8
9
10
11

‍

我们重新运行测试方法,可以看到运行结果没有变化。

‍

‍

‍

# foreach标签

使用if,我们可以解决传入一个参数的情况;但有时候,我们需要用到传入多个参数,例如:

select * from user where id in (41, 42, 43);
1

那这种情况该怎么传参呢?

‍

‍

我们这里使用QueryVo为例,添加一个List:

public class QueryVo {
    private User user;
    private List<Integer> ids;
}
1
2
3
4

请读者自行添加getter 和 setter

‍

‍

我们在接口IUserDao.java里添加一个方法:

/**
 * 根据QueryVo提供的id集合,查询用户信息
 * @param vo
 * @return
 */
List<User> findUserInIds(QueryVo vo );
1
2
3
4
5
6

‍

然后,我们就可以使用Mybatis提供的foreach标签了:该标签能遍历一个集合

<!-- 根据QueryVo中的id集合,实现查询用户列表 -->
<select id="findUserInIds" resultType="USER" resultMap="userMap" parameterType="QueryVo">
    select * from user
    <where>
        <if test="ids != null and ids.size() > 0">
            <foreach collection="ids" open="and id in (" close=")" item="uid" separator=",">
                #{uid}
            </foreach>
        </if>
    </where>
</select>
1
2
3
4
5
6
7
8
9
10
11

collection属性表示这是一个集合,open 表示开始,close表示结束,items就是要填充的内容,分隔符是逗号

‍

‍

然后我们写一个测试方法:

@Test
public void testFindUserInIds(){
    List<Integer> list = new ArrayList<>();
    list.add(41);
    list.add(42);
    list.add(43);

    QueryVo vo = new QueryVo();
    vo.setIds(list);

    List<User> users = userDao.findUserInIds(vo);
    for(User u : users){
        System.out.println(u);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

‍

‍

运行结果:

 - ==>  Preparing: select * from user WHERE id in ( ? , ? , ? )
 - ==> Parameters: 41(Integer), 42(Integer), 43(Integer)
 - <==      Total: 3
1
2
3

可以看到能正常查询

‍

‍

‍

# sql标签

纵观我们的IUserDao.xml文件,几乎每个select标签都是以 select * from user​开头的,此时我们可以抽取重复的部分:在IUserDao.xml下新建一个sql标签,内容写我们希望抽取的内容

<sql id="defaultUser">
    select * from user
</sql>
1
2
3

注意:抽取了代码片段后,里面不能写分号,不然拼接会出错的

‍

‍

然后,我们就可以在select标签里引用了:

<!-- 配置查询所有用户,id要写方法名称-->
<select id="findAll" resultMap="userMap">
    <include refid="defaultUser"/>
</select>

<!-- 根据QueryVo中的id集合,实现查询用户列表 -->
<select id="findUserInIds" resultType="USER" resultMap="userMap" parameterType="QueryVo">
    <include refid="defaultUser"/>
    <where>
        <if test="ids != null and ids.size() > 0">
            <foreach collection="ids" open="and id in (" close=")" item="uid" separator=",">
                #{uid}
            </foreach>
        </if>
    </where>
</select>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

‍

该标签了解即可,用的较少。

‍

‍

# 源码

本文所有代码已上传到了GitHub (opens new window)和Gitee (opens new window)上,并且创建了分支demo13,读者可以通过切换分支来查看本文的示例代码。

在GitHub上编辑此页 (opens new window)
上次更新: 2023/5/15 16:02:46
Mybatis与JNDI
Mybatis多表查询

← Mybatis与JNDI Mybatis多表查询→

Theme by Vdoing | Copyright © 2022-2023 粤ICP备2022067627号-1 粤公网安备 44011302003646号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式