第七个Mybatis程序-动态SQL

动态sql就是根据不同的条件生成不同的sql语句
但是为什么要使用它?原因很简单,当我们百度的时候,输入一个人名,可能会出现多个人,但是如果知道他的演员,我们在输入的人名后面加上演员,就可以直接搜索到,不需要再去筛选。
实际在这里就使用了动态SQL,当我们只输入人名的时候,sql语句可能是

select * from table where name=#{name}

如果再加入演员的话,sql语句可能变成

select * from table where name=#{name} and job=#{actor}

在这里,我们的sql语句都使用了动态拼接。

name=#{name} 
name=#{name} and job=#{job}

在Mybatis中,动态SQL已经成为了它最强大的特性之一,而Mybatis3中采用了功能强大的OGNL表达式来完成动态sql

简单了解OGNL表达式:
对象导航图语言(Object Graph Navigation Language),简称OGNL,是应用于Java中的一个开源的表达式语言(Expression Language),它被集成在Struts2等框架中,作用是对数据进行访问,它拥有类型转换、访问对象方法、操作集合对象等功能。

知识点主要如下:(每个元素都有<>包裹,csdn打不出来)

  • if:判断语句,用于单条件分支判断
  • choose(when、otherwise):用于多条件分支判断
  • where、trim、set:辅助元素,用于处理SQL拼接、特殊字段问题
  • foreach:循环语句,常用于in语句等列举条件中
  • bind:从OGNL表达式中创建一个变量,且绑定到上下文,常用于模糊查询的SQL中

一、if

在Mybatis中,if元素是常用的判断语句,主要用于实现简单的条件选择。在实际应用中,我们可能通过多个条件来精确地查询某个数据。

如何使用:

1、搭建一个数据库
在这里插入图片描述

2、搭建配置文件

<!--加入日志工厂设置-->
	<settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

3、编写工具类
4、创建实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Book {
    private int id;
    private String name;
    private double price;
    private int bookCount;
    private String author;
}

5、创建dao接口

public interface BookMapper {
    //if查询
    List<Book> query(Book book);
    //choose查询
    List<Book> query2(Book book);
    //where+if
    List<Book> query3(Book book);
    //where+trim
    List<Book> query4(Book book);
    //update
    int set(Book book);
    //foreach遍历
    List<Book> query5(List list);
    //bind
    List<Book> query6(Book book);
}

实现接口

<select id="query" parameterType="book" resultType="book">
        select *
        from mydatabase.book 
        where 1=1
        <if test="name!=null and name!=''">
            and name=#{name}<!--也可以加入like %name%模糊查询-->
        </if>
        <if test="price!=null and price!=''">
            and price=#{price}
        </if>
        <if test="bookCount!=null and bookCount!=''">
            and bookCount=#{bookCount}
        </if>
        <if test="author!=null and author!=''">
            and author=#{author}
        </if>
    </select>

6、注册Mapper

	<mappers>
        <mapper class="com.dao.BookMapper"/>
    </mappers>

7、测试
在这里插入图片描述
通过实体类的set方法,去传入我们要查询的值,这样可以精确查找
在这里插入图片描述

二、choose、when、otherwise

为什么使用它们?

在使用if元素时,只要test属性中的表达式为true,就会执行元素中的条件语句,但是在实际应用当中,有时只需要从多个选项中选择一个执行。
例如:

  • 如果name不为空,则值根据name进行筛选;
  • 如果name为空,price不为空,则只根据price进行筛选;
  • 如果name和price和其他的属性字段都为空,则要求查询出所有的信息!
<!--choose-->
    <select id="query2" resultType="book" parameterType="book">
        select *
        from mydatabase.book
        where 1=1
        <choose>
            <when test="name!=null and name!=''">
                and name like concat('%',#{name},'%')
            </when>
            <when test="price!=null and price!=''">
                and price=#{price}
            </when>
            <when test="author!=null and author!=''">
                and author like  concat('%',#{author},'%')
            </when>
            <otherwise>
                and bookCount is not null
            </otherwise>
        </choose>
	</select>

测试:

@Test
    public void test2(){
        BookMapper mapper = MybatisUtil.getSqlSession().getMapper(BookMapper.class);
        Book book = new Book();
        book.setAuthor("白");
        for (Book book1 : mapper.query2(book)) {
            System.out.println(book1);
        }
    }

在这里插入图片描述

@Test
    public void test2(){
        BookMapper mapper = MybatisUtil.getSqlSession().getMapper(BookMapper.class);
        Book book = new Book();
        book.setAuthor("白");
        book.setName("无");
        for (Book book1 : mapper.query2(book)) {
            System.out.println(book1);
        }
    }

结果:
在这里插入图片描述
可以观察得出,choose是选择其中的一个sql字段去查询,而不是像if元素一样,只要在set中传入了值,就将传入值的if元素中的sql字段全部拼接在一起,达到精确查询。
在上述代码中,使用了choose元素进行sql拼接,
如果第一个when元素中的条件为真,则只动态拼接第一个when元素内的sql片段,否则继续向下判断。
如果前面所有when元素中的条件都不为真,则只拼接otherwise元素内的sql片段。

三、where、trim

前面的查询中,映射文件中编写的sql后面都加入了1=1的条件判断语句,是为了保证当条件不成立时拼接起来的sql语句在执行时不报错,即 使得sql不出现语法错误。
那么在Mybatis中,有没有办法不用加入1=1这样的条件呢?针对这种情况,Mybatis中提供了where元素

1、where+if

<!--where+if-->
    <select id="query3" parameterType="book" resultType="book">
        select *
        from mydatabase.book
        <where>
            <if test="name!=null and name!=''">
                and name=#{name}
            </if>
            <if test="author!=null and author!=''">
                and author=#{author}
            </if>
        </where>
    </select>
@Test
    public void test3(){
        BookMapper mapper = MybatisUtil.getSqlSession().getMapper(BookMapper.class);
        Book book = new Book();
        book.setName("无题");
        book.setAuthor("李白");
        for (Book book1 : mapper.query3(book)) {
            System.out.println(book1);
        }
    }

结果:
在这里插入图片描述

2、where+trim(重点)

<trim prefix="str1" prefixOverrides="str2"/> 

trim中的prefix="str1"表示,语句的前缀,它会在拼接的时候,str1自动加到if中的sql语句前面
prefixOverrides="str2"表示,去除语句的等于str2的特殊字符串,在拼接的sql语句的时候,将str2去除。
这个元素,一般是用来定制查询的作用!

<!--where+trim-->
    <select id="query4" resultType="book" parameterType="book">
        select *
        from mydatabase.book
        <where>
            <trim prefix="where" prefixOverrides="and"/>
            <if test="name!=null and name!=''">
                and name=#{name}
            </if>
            <if test="author!=null and author!=''">
                and author=#{author}
            </if>
        </where>
    </select>
@Test
    public void test4(){
        BookMapper mapper = MybatisUtil.getSqlSession().getMapper(BookMapper.class);
        Book book = new Book();
        book.setName("无题");
        book.setAuthor("李白");
        for (Book book1 : mapper.query4(book)) {
            System.out.println(book1);
        }
    }

结果:
在这里插入图片描述
1=1,where+if,where+trim的查询结果均相同,什么时候该用什么,全看自己的选择了,一般用where+trim比较好,它可以定制sql语句,但是1=1一般比较简单,全看自己的取舍了。

四、set

一般,我们在数据库的操作中,总是需要更改一些信息,Mybatis给我们提供了set元素,可以动态的拼接更新信息的操作

foreach:

  • item:循环中当前的元素
  • index:当前元素在集合中的位置下标
  • collection:可以是一个array、list、collection、map集合的键、pojo包装类中的数组或集合类型的属性名
  • open和close:以什么符号将这些元素包装起来
  • separator:各个元素的间隔符
	<update id="set" parameterType="book">
        update mydatabase.book
        <set>
            <if test="name!=null and name!=''">
                name=#{name},
            </if>
            <if test="price!=null and price!=''">
                price=#{price},
            </if>
            <if test="bookCount!=null and bookCount!=''">
                bookCount=#{bookCount},
            </if>
            <if test="author!=null and author!=''">
                author=#{author},
            </if>
        </set>
        where id=#{id}
    </update>
@Test
    public void test5(){
        BookMapper mapper = MybatisUtil.getSqlSession().getMapper(BookMapper.class);
        Book book = new Book();
        book.setAuthor("张若虚");
        book.setName("春江花月夜");
        book.setId(2);
        mapper.set(book);
        for (Book book1 : mapper.query(new Book())) {
            System.out.println(book1);
        }
    }

结果:
在这里插入图片描述
Mybatis中的set元素,主要作用是动态的包含sql语句前输出一个set关键字,并且将sql语句中的最后一个多余的逗号去除!
在编写sql语句的时候,记得在所有的sql语句后面加入逗号’,’,如果不加会报错
而且在传入值的时候,不能都为空,如果全为空,也会报错。

五、foreach

foreach元素一般用来遍历数组和集合,假设有上千条数据,我们可以可以用foreach全部查询出来

<!--foreach-->
    <select id="query5" parameterType="list" resultType="book">
        select * from mydatabase.book where id in
        <foreach collection="list" index="index" item="id" open="(" separator="," close=")">
            #{id}
        </foreach>
    </select>
@Test
    public void test6(){
        BookMapper mapper = MybatisUtil.getSqlSession().getMapper(BookMapper.class);
        ArrayList<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        for (Book book : mapper.query5(list)) {
            System.out.println(book);
        }
    }

结果:在这里插入图片描述

注意:

collection属性:

  • 如果传入的是单参数且参数类型是一个数组或者List的时候,collection属性值分别为array、list(或collection)
  • 如果传入的参数有多个,就需要把它们封装成一个Map,单参数也可以封装成Map集合,这是collection的属性值就为Map的键
  • 如果传入的参数是pojo包装类,collection属性值就为该包装类中需要遍历的数组或集合的属性名

六、bind(了解即可)

在进行模糊查询的时候
如果使用${}进行字符串拼接,则无法防止sql注入问题
如果使用concat函数进行拼接,则只针对mysql数据库有效,对别的数据库无效。
映射文件中的sql就要根据不同的情况提供不同形式的实现,显然是不可能的,非常的麻烦,且不利于项目的移植。
所以,Mybatis提供了bind元素来解决这个问题,完全不需要使用数据库语言,只要使用Mybatis的语言即可与所需参数连接!

<!--bind-->
    <select id="query6" resultType="book" parameterType="book">
        <bind name="_name" value="'%'+name+'%'"/>
        select *
        from mydatabase.book
        where name like #{_name}
    </select>
 @Test
    public void test7(){
        BookMapper mapper = MybatisUtil.getSqlSession().getMapper(BookMapper.class);
        Book book = new Book();
        book.setName("春");
        for (Book book1 : mapper.query6(book)) {
            System.out.println(book1);
        }
    }

结果:
在这里插入图片描述
bind实际就是运用了一个ref(引用),将sql语段拼接进去

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值