0.数据库准备

新建一个表并初始化数据。

  1. create table activebooks(
  2. UUID varchar(36) primary key,
  3. name varchar(20),
  4. type varchar(10),
  5. author varchar(10)
  6. )
insert into mybatis.activebooks
VALUES (UUID(), 'book1', 1, '小明'),
       (UUID(), 'book2', 1, '小红'),
       (UUID(), 'book3', 2, '小明'),
       (UUID(), 'book4', 2, '小红')

当然,对于实体类等需要重新搭建的在前文已经说明如何搭建,这里不再赘述。

1.IF

现有这样一个需求:查询指定类型和作者的图书信息。但需要注意的是,希望如果查询时不输入类型就只根据作者查询,反之亦然。
我们知道,如果两个参数都传的话,SQL语句应该是这样的:

select * from activebooks where author='小明' and type=1

如果说不传作者参数、只传类型参数的话,SQL语句应该变成这样:

select * from activebooks where type=1

也就是说在MyBatis中, author=#{}这句话不应该输出。
MyBatis提供了IF标签实现这种操作。

<select id="ifTest" resultType="pojo.Books">
  select * from mybatis.activebooks where 1=1
  <if test="author != null">and author=#{author}</if>
  <if test="type != null">and type=#{type}</if>
</select>

IF标签的作用是判断test中的条件,比如Line 3是判断author如果不为空,就拼接后面的语句。

这里的 where 1=1 的作用为便于后两行and的拼接,如果没有 1=1 的判断的话,这句话就变成了 where and,这句SQL语句是错的(where不能直接接and),所以使用1=1(也就是一定为真的语句)来避免对and的麻烦处理。

使用测试类进行测试。

如果想要查看最后执行的语句,需要使用日志工具(比如log4j等)输出日志即可。

image.png
image.png

2.WHERE

上面的例子使用了1=1来处理and(or同理)可能存在的潜在问题。当然MyBatis也提供了where标签来更好的解决这一问题。
将上例的SQL改写:

<select id="ifTest" resultType="pojo.Books">
  select * from mybatis.activebooks
  <where>
    <if test="author != null">and author=#{author}</if>
    <if test="type != null">and type=#{type}</if>
  </where>
</select>

where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。

3.SET

同理,当进行update更新操作时会用到set。
现有需求:更新author和type,如果传参则更改,如果不传则不变。
SQL语句如下:

<update id="setTest" parameterType="pojo.Books">
  update mybatis.activebooks
  <set>
    <if test="type != null">type = #{type},</if>
    <if test="author != null">author = #{author}</if>
  </set>
  where name = #{name};
</update>

当然,这里在写接口和测试类的时候会有变化,可以先自行尝试调整(关于返回值问题和输出问题), 如果没有头绪或者测试失败请看示例接口和测试类。

    void setTest(@Param("author") String author,@Param("type") String type,@Param("name")String name);
@Test
public void setTest() {
    SqlSession sqlSession = MybatisUtil.getSqlSession();
    BookMapper mapper = sqlSession.getMapper(BookMapper.class);
    mapper.setTest(null,"2","book2");
    sqlSession.commit();
    sqlSession.close();
}
使用上述代码测试:<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/12434244/1646295356184-028fdbf2-4f76-4cd4-bf12-68125661afdb.png#clientId=ucab75db3-5461-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=43&id=u4e3cffef&margin=%5Bobject%20Object%5D&name=image.png&originHeight=86&originWidth=1211&originalType=binary&ratio=1&rotation=0&showTitle=true&size=23175&status=done&style=none&taskId=u771bf36d-9eb0-40ff-bd84-845bea0b490&title=log4j2%E8%BE%93%E5%87%BASQL%E8%AF%AD%E5%8F%A5&width=606 "log4j2输出SQL语句")<br />![QQ截图20220303161755.png](https://cdn.nlark.com/yuque/0/2022/png/12434244/1646295499018-cedaf21d-f377-46ff-8f02-f257403011b6.png#clientId=ucab75db3-5461-4&crop=0&crop=0&crop=1&crop=1&from=ui&id=n0mxT&margin=%5Bobject%20Object%5D&name=QQ%E6%88%AA%E5%9B%BE20220303161755.png&originHeight=163&originWidth=661&originalType=binary&ratio=1&rotation=0&showTitle=true&size=20168&status=done&style=none&taskId=uff811a93-1e9a-4f9f-b11f-d25691ac6cf&title=%E7%BB%93%E6%9E%9C%E6%88%90%E5%8A%9F%E6%9B%B4%E6%94%B9 "结果成功更改")

4.CHOOSE

有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
现有需求:查询指定类型和作者的图书信息。但需要注意的是,希望如果查询时不输入类型就只根据作者查询,反之亦然。但是当两者都没有传参的时候就查询出book1一条结果。
SQL语句如下:

<select id="chooseTest" resultType="pojo.Books">
    select * from mybatis.activebooks
    <where>
        <choose>
            <when test="author != null">author=#{author}</when>
            <when test="type != null">and type=#{type}</when>
            <otherwise>and name='book1'</otherwise>
        </choose>
    </where>
</select>

使用上述代码测试,注意观察传参和拼接出的SQL语句的关系:
image.png
image.png
image.png
image.png
通过上面的测试用例,不难发现,当两个参数都传的情况下的结果和只传第一项结果是相同的。这也体现了为什么说有点类似Java的switch语句。

5.FOREACH

动态 SQL 的另一个常见使用场景是对集合进行遍历。 foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。

官方文档的说明貌似有点云里雾里,其实简单来说就是实现遍历功能。
比如说这样一个需求:需要查询名称分别为book1、book2、book3的具体信息。
如果只是写SQL的话,大体应该是这样:

select * from mybatis.activebooks where name='book1' or name='book2' or name='book3'

那么使用foreach这样实现:

<select id="forEachTest" parameterType="map" resultType="pojo.Books">
  select * from mybatis.activebooks
  <where>
    <!--说明摘自狂神说
            collection:指定输入对象中的集合属性
            item:每次遍历生成的对象
            open:开始遍历时的拼接字符串
            close:结束时拼接的字符串
            separator:遍历对象之间需要拼接的字符串
          -->
    <foreach collection="names"  item="name" open="and (" close=")" separator="or">
      name=#{name}
    </foreach>
  </where>
</select>

注:这里接口的参数用的是map

编写测试类测试:

@Test
public void forEachTest(){
  SqlSession sqlSession = MybatisUtil.getSqlSession();
  BookMapper mapper = sqlSession.getMapper(BookMapper.class);
  HashMap map = new HashMap();
  List<String> names = new ArrayList<String>();
  names.add("book1");
  names.add("book2");
  names.add("book3");
  map.put("names",names);
  List<Books> books=mapper.forEachTest(map);
  System.out.println(books);
  sqlSession.close();
}

image.png