【MyBatis】第七篇:动态sql

mybatis中的动态sql,其实就是在mybatis中映射配置文件中通过if等判断语句写sql。现在聊一下,常用的的判断语句。

前面准备:

CREATE TABLE `student` (
  `sid` int DEFAULT NULL,
  `sname` varchar(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
  `sage` int DEFAULT NULL,
  `ssex` varchar(2) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
  `gid` int DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;

 
insert  into `student`(`sid`,`sname`,`sage`,`ssex`,`gid`) values 

(1,'张三',18,'男',2),

(2,'赛貂蝉',14,'女',1),

(3,'胡铁花',23,'男',2),

(4,'白飞飞',16,'女',1),

(5,'李寻欢',16,'男',1),

(4,'宫崎',18,'男',2);



if

if标签是通过test数据的表达式进行判断,如果true就执行其标签中的内容,如果false则向反。

常用场景如下,比如在很多伤害数据库中的字段的条件为NULL的时候会影响结果。保留web项目中,前端传递的参数又三个条件,但是三个条件不一定都会被用户选择。然后生成不同的sql从数据库中取出数据。

当然也可以通过如果通过java代码进行判断,然后也可以解决这个问题,不过mybatis的通过xml配置sql语句,所以可能会更直观方便一些。

映射文件:

 <select id="getStudent" resultType="Student">
          <!--   为什么会写 1=1 因为比如例子中sql的条件会通过and 连接 防止出现问题采用这个方法 -->
          SELECT  sid ,  sname ,  sage ,  ssex ,  gid  FROM  testmybatis.student WHERE 1=1
          <if test="sid!='' and sid !=null">
              and sid=#{sid}
          </if>
          <if test="sname!='' and sname !=null">
              and sname=#{sname}
          </if>
          <if test="sage!='' and sage !=null">
              and sage=#{sage}
          </if>
          <if test="ssex!='' and ssex !=null">
              and ssex=#{ssex}
          </if>
          <if test="gid!='' and gid !=null">
              and gid=#{gid}
          </if>
      </select>

映射接口类中的方法:

    List<Student>  getStudent(Student student);

调用方法:

  Student student=new Student(null,null,null,"女",null);
        System.out.println("  --------------------       " +  studentMapper.getStudent(student) );

在这里插入图片描述

注意:

  • if中的test属性表达式中,直接用对象的属性进行判断,不需要通过#{}或者${}.
  • 一般因为有连接关键字,所以在where后面会通过一个伪条件而实现动态代码。

where标签

当然如果不想在where中天津一个伪条件的话,还可以通过where标签进行实现,具体如下:

 <select id="getStudent" resultType="Student">
          <!--   为什么会写 1=1 因为比如例子中sql的条件会通过and 连接 防止出现问题采用这个方法 -->
          SELECT  sid ,  sname ,  sage ,  ssex ,  gid  FROM  testmybatis.student
              <where>
                  <if test="sid!='' and sid !=null">
                      sid=#{sid}
                  </if>
                  <if test="sname!='' and sname !=null">
                      and sname=#{sname}
                  </if>
                  <if test="sage!='' and sage !=null">
                      and sage=#{sage}
                  </if>
                  <if test="ssex!='' and ssex !=null">
                      and ssex=#{ssex}
                  </if>
                  <if test="gid!='' and gid !=null">
                      and gid=#{gid}
                  </if>
              </where>

      </select>

然后看一下结果,现在换成性别为男:

在这里插入图片描述

也是没有问题,这个时候可以看出where标签有两个作用:

  • 第一:sql语句需要些where 关键字,where标签会自动添加这个关键字。
  • 第二:如果第一个条件不成立,而导致where后面and关键字的话,where标签会自动将首个and优化掉,让sql符合要求。而这种取消,只是取消条件的前面and。

如果这样写呢?把and放在后面。

<select id="getStudent" resultType="Student">
        <!--   为什么会写 1=1 因为比如例子中sql的条件会通过and 连接 防止出现问题采用这个方法 -->
        SELECT sid , sname , sage , ssex , gid FROM testmybatis.student
        <where>
            <if test="sid!='' and sid !=null">
                sid=#{sid} and
            </if>
            <if test="sname!='' and sname !=null">
                sname=#{sname} and
            </if>
            <if test="sage!='' and sage !=null">
                sage=#{sage} and
            </if>
            <if test="ssex!='' and ssex !=null">
                ssex=#{ssex} and
            </if>
            <if test="gid!='' and gid !=null">
                gid=#{gid}
            </if>
        </where>

    </select>

在这里插入图片描述

直接保存了,而这个时候需要使用另一个标签trim。

trim

先看一下trim标签:

在这里插入图片描述

可以看出trim标签有四个属性。具体有什么用呢?

属性描述
prefix在tirm标中的内容前添加指定内容
prefixOverrides在tirm标中的内容后添加指定内容
suffix在tirm标中的内容前面删除指定内容
suffixOverrides在tirm标中的内容后面删除指定内容

看着有些绕,还是老规矩用代码演示:

 <select id="getStudent" resultType="Student">
        <!--   为什么会写 1=1 因为比如例子中sql的条件会通过and 连接 防止出现问题采用这个方法 -->
        SELECT sid , sname , sage , ssex , gid FROM testmybatis.student
        <trim prefix="where" suffixOverrides="and">
            <if test="sid!='' and sid !=null">
                sid=#{sid} and
            </if>
            <if test="sname!='' and sname !=null">
                sname=#{sname} and
            </if>
            <if test="sage!='' and sage !=null">
                sage=#{sage} and
            </if>
            <if test="ssex!='' and ssex !=null">
                ssex=#{ssex} and
            </if>
            <if test="gid!='' and gid !=null">
                gid=#{gid}
            </if>
        </trim>

    </select>

看一下结果:

在这里插入图片描述

解读

<trim prefix="where" suffixOverrides="and">

因为trim标签不会主动添加where ,所以需要通过prefix在条件语句前面添加where。因为and是写在后面的,如果最后出现and会影响sql语句,所以通过设置suffixOverrides来将最后面的and删除,如果没有也就不必删除了

choose —when—otherwise

这个语句判断记住一点其更像是是java中switch–case—default。

意思就是所有的条件,只要最上面的满足后面的就直接跳出。

<select id="getStudent" resultType="Student">
        <!--   为什么会写 1=1 因为比如例子中sql的条件会通过and 连接 防止出现问题采用这个方法 -->
        SELECT sid , sname , sage , ssex , gid FROM testmybatis.student
        <where >

    <choose>
        <when test="sid!='' and sid !=null">
            <!-- 因为只会判断一个条件满足,所以不需要添加and这样的连接符 -->
            sid=#{sid}
        </when>
        <when test="sname!='' and sname !=null">
            sname=#{sname}
        </when>
        <when test="sage!='' and sage !=null">
            sage=#{sage}
        </when>
        <when test="ssex!='' and ssex !=null">
            ssex=#{ssex}
        </when>
        <otherwise>
            gid=#{gid}
        </otherwise>
    </choose>

</where>
</select>

然后调用方法:

  Student student=new Student(null,null,14,"男",null);
        System.out.println("  --------------------       " +  studentMapper.getStudent(student) );

然后看一下结果:

在这里插入图片描述

这里注意数据库中没有男性14岁的学生,而且性别为男的条件也没有其效果,所以说只会选择一个条件。

注意:choose中的必须有一个when标签,而otherwise标签最多只有一个

foreach

这个标签看见就知道是一个循环语句,具体是如何用呢?看实例吧。

foreach 元素的属性主要有 item,index,collection,open,separator,close。

属性描述
item表示集合中没一个元素的迭代的名字,这个在jsp中也有。毕竟这个元素有可能是一个对象,方便取出属性值。
index指定一个名字,用户表示在迭代过程中,每次迭代到的位置,可以理解为for(int i=0;i++;i<5)中的i。可以为起一个名字。
open表示该语句什么时候开始
separator表述迭代数据中间用什么内容作为分隔符。
close表示什么时候结束

还是老规矩,用代码演示:

先创建一个list,然后用来插入演示:

 List<Student> list=new ArrayList<Student>();
        list.add(new Student(null,"v胖",3,"男",3));
        list.add(new Student(null,"奎爷",33,"男",1));
        list.add(new Student(null,"娜美",15,"女",3));
        studentMapper.insertListStudent(list);
  <insert id="insertListStudent">
       INSERT INTO  testmybatis.student ( sid ,  sname ,  sage ,  ssex ,  gid ) VALUES
       <foreach collection="studentList" item="student"   separator="," >
             <!--sql插入数应该有一对() 不可以使用 open和close会在前后放内容,包裹整个数据,比如应该是(student),(student),(student) 却变成(student,student,student)-->
          ( #{student.sid}, #{student.sname}, #{student.sage}, #{student.ssex}, #{student.gid})
       </foreach>
                                                                      
   </insert>

接口类的方法:

 void insertListStudent(@Param("studentList") List<Student> studentList);

运行结果:

在这里插入图片描述

现在来一个批量删除的操作,这个可以使用多个属性如下操作:

   void deleteArr(@Param("arr") int[]  arr);
 <delete id="deleteArr">
      delete from student where sid in
        <foreach collection="arr" separator="," open="(" close=")" item="sid">
            #{sid}
        </foreach>
    </delete>

然后调用方法:

        int[] arr={12,13,14};
        studentMapper.deleteArr(arr);

现在看一下结果:

在这里插入图片描述

所以可以看在foreach中的open和close的具体效果。

sql

还有一个sql标签,这个标签可以记录一段sql,在需要使用的适合用incluede标签进行引用。

还是老规矩,进程代码演示,用上面的例子进行演示:

先不用sql的如下:

<select id="getStudent" resultType="Student">
        <!--   为什么会写 1=1 因为比如例子中sql的条件会通过and 连接 防止出现问题采用这个方法 -->
        SELECT sid , sname , sage , ssex , gid FROM testmybatis.student
        <where >

    <choose>
        <when test="sid!='' and sid !=null">
            <!-- 因为只会判断一个条件满足,所以不需要添加and这样的连接符 -->
            sid=#{sid}
        </when>
        <when test="sname!='' and sname !=null">
            sname=#{sname}
        </when>
        <when test="sage!='' and sage !=null">
            sage=#{sage}
        </when>
        <when test="ssex!='' and ssex !=null">
            ssex=#{ssex}
        </when>
        <otherwise>
            gid=#{gid}
        </otherwise>
    </choose>

</where>
</select>

然后是使用sql标签的:

<select id="getStudent" resultType="Student">
        <!--   为什么会写 1=1 因为比如例子中sql的条件会通过and 连接 防止出现问题采用这个方法 -->
        SELECT <include refid="studentColumns"></include> FROM testmybatis.student
        <where>

            <choose>
                <when test="sid!='' and sid !=null">
                    <!-- 因为只会判断一个条件满足,所以不需要添加and这样的连接符 -->
                    sid=#{sid}
                </when>
                <when test="sname!='' and sname !=null">
                    sname=#{sname}
                </when>
                <when test="sage!='' and sage !=null">
                    sage=#{sage}
                </when>
                <when test="ssex!='' and ssex !=null">
                    ssex=#{ssex}
                </when>
                <otherwise>
                    gid=#{gid}
                </otherwise>
            </choose>

        </where>

这样方便将一些常用的sql公用部分拆出来,然后进行使用,有点像是java中的公共方法提出的感觉,这样方便使用。

script

这个标签是搭配着注解使用的,还是老规矩进行代码演示:

  @Delete(" <script>" +
            "delete from student where sid in " +
            "<foreach collection=\"arr\" separator=\",\" open=\"(\" close=\")\" item=\"sid\"> " +
            " #{sid} " +
            "  </foreach>" +
            " </script>")
    
    void deleteArr(@Param("arr") int[]  arr);

可以看出通过script标签可以将本来在xml中写的配置信息,通过注解写在java文件中,虽然方便但是说实话没有通过xml看着配置信息清晰。

bind 标签

元素允许你在 OGNL 表达式以外创建一个变量,并将其绑定到当前的上下文。

然后简单演示:

  <select id="selectStudentLike" resultType="Student">
        <bind name="pattern" value="'%' + name + '%'" />
        SELECT * FROM student
        WHERE sname LIKE #{pattern}
    </select>
    List<Student>  selectStudentLike(  Map<String, String> params);
   Map<String, String> params =new HashMap();
        params.put("name", "三");
        List<Student> studentList = studentMapper.selectStudentLike(params);
        System.out.println(studentList);

看一下结果:

在这里插入图片描述

不过出发在一个sql中使用了多次某个片段,不然不如直接写的方便。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值