Mybatis多表关联查询与动态SQL(下)

简介: Mybatis多表关联查询与动态SQL

Mybatis多表关联查询与动态SQL(上):https://developer.aliyun.com/article/1509367

2.0、MySQL环境与前置要求

数据与SQL环境如下:

2.1、什么是动态SQL

MyBatis的动态SQL是基于OGNL的表达式的。它对SQL语句进行灵活的操作,通过表达式判断来实现对SQL的灵活拼接、组装。

mybatis核心对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接、组装。

主要通过以下标签:if,where,choose(when,otherwise),trim,set,foreach。

2.2、if条件判断

根据 name和 sex 来查询数据。如果name为空,那么将只根据sex来查询;反之只根据name来查询

首先不使用 动态SQL 来书写

接口:

    /**
     * 根据学生姓名和性别获得学生集合
     */
    List<Student> selectStudentsByNameAndSex(@Param("name") String name,@Param("sex") String sex);
映射:

    <select id="selectStudentsByNameAndSex" resultType="student">
        SELECT id,name,sex from student where name=#{name} and sex=#{sex};
    </select>

测试:

/**

  • Method: selectStudentsByNameAndSex
    */

@Test

public void testSelectStudentsByNameAndSex() throws Exception {

List students=dao.selectStudentsByNameAndSex(“rose”,null);

System.out.println(students);

Assert.assertNotNull(students);

}

上面的查询语句,我们发现如果 #{sex} 为空,那么查询结果也是空,如何解决这个问题呢?使用 if 来判断

<select id="selectStudentsByNameAndSex" resultType="student">

    SELECT id,name,sex from student where 1=1
    <!--如果test为真会输出中间的内容-->
    <if test="name!=null and name!=''">
        and name=#{name}
    </if>

    <if test="sex!=null and sex!=''">
        and sex=#{sex}
    </if>

</select>



<!-- 2 if(判断参数) - 将实体类不为空的属性作为where条件 -->
<select id="getStudentList_if" resultMap="resultMap_studentEntity" parameterType="liming.student.manager.data.model.StudentEntity">
 SELECT ST.STUDENT_ID,
 ST.STUDENT_NAME,
 ST.STUDENT_SEX,
 ST.STUDENT_BIRTHDAY,
 ST.STUDENT_PHOTO,
 ST.CLASS_ID,
 ST.PLACE_ID
 FROM STUDENT_TBL ST
 WHERE
 <if test="studentName !=null ">
 ST.STUDENT_NAME LIKE CONCAT(CONCAT('%', #{studentName, jdbcType=VARCHAR}),'%')
 </if>
 <if test="studentSex != null and studentSex != '' ">
 AND ST.STUDENT_SEX = #{studentSex, jdbcType=INTEGER}
 </if>
 <if test="studentBirthday != null ">
 AND ST.STUDENT_BIRTHDAY = #{studentBirthday, jdbcType=DATE}
 </if>
 <if test="classId != null and classId!= '' ">
 AND ST.CLASS_ID = #{classId, jdbcType=VARCHAR}
 </if>
 <if test="classEntity != null and classEntity.classId !=null and classEntity.classId !=' ' ">
 AND ST.CLASS_ID = #{classEntity.classId, jdbcType=VARCHAR}
 </if>
 <if test="placeId != null and placeId != '' ">
 AND ST.PLACE_ID = #{placeId, jdbcType=VARCHAR}
 </if>
 <if test="placeEntity != null and placeEntity.placeId != null and placeEntity.placeId != '' ">
 AND ST.PLACE_ID = #{placeEntity.placeId, jdbcType=VARCHAR}
 </if>
 <if test="studentId != null and studentId != '' ">
 AND ST.STUDENT_ID = #{studentId, jdbcType=VARCHAR}
 </if>
</select> 
 虽然1=1这种方法结合if可以解决我们的需求,但是1=1明显是冗余的,通过where可以解决。

2.3、where条件

where 元素知道只有在一个以上的if条件有值的情况下才去插入“WHERE”子句,若最后的内容是“AND”或“OR”开头的,where 元素也知道如何将他们去除。

修改后的映射:

SELECT id,name,sex from student

<!--1、如果两个if只要有一个有输出就会在sql中添加 where-->
<where>
    <if test="name!=null and name!=''">
        <!--2、如果where后以and或or开始则会删除and或or-->
        and name like concat(concat('%',#{name}),'%');
    </if>

    <if test="sex!=null and sex!=''">
        and sex=#{sex}
    </if>
</where>

这个“where”标签会知道如果它包含的标签中有返回值的话,它就插入一个‘where’。此外,如果标签返回的内容是以AND 或OR 开头的,则它会剔除掉。


where标记的作用类似于动态sql中的set标记,他的作用主要是用来简化sql语句中where条件判断的书写的,如下所示:


    select * from user

    

      id=#{id}

      and name=#{name}

      and gender = #{gender}

where 标记会自动将其后第一个条件的and或者是or给忽略掉

2.4、if+set设置值

当update语句中没有使用if标签时,如果有一个参数为null,都会导致错误。

当在update语句中使用if标签时,如果前面的if没有执行,则或导致逗号多余错误。使用set标签可以将动态的配置SET 关键字,和剔除追加到条件末尾的任何不相关的逗号。如果set包含的内容为空的话则会出错。


使用if+set标签修改后,如果某项为null则不进行更新,而是保持数据库原值。


如果通过if判断表面可以解决问题,如下所示:

update student set

<if test="name!=null and name.lenght()>0">
    name=#{name} ,
</if>

<if test="sex!=null and sex.lenght()>0">
    sex=#{sex}
</if>

where id=#{id}

这样做也会有问题,就是当sex为空时的sql就变成了 update student set name=#{name} , where id=#{id},这明显是错误的。


同理,上面的对于查询 SQL 语句包含 where 关键字,如果在进行更新操作的时候,含有 set 关键词,我们怎么处理呢?


接口:

/**
 * 更新学生
 */
int updateStudent(Student entity);

映射:

update student name=#{name}设置标签

    <if test="sex!=null and sex.length()>0">
        sex=#{sex}
    </if>
</set>
where id=#{id}

注意:某些情况下逗号必须添加,如下所示:

update student name=#{name} ,

    <if test="sex!=null and sex.length()>0">
        sex=#{sex} ,
    </if>
</set>
where id=#{id}

这样写,如果第一个条件 name 为空,那么 sql 语句为:update student set sex=? where id=?


如果第一个条件不为空,那么 sql 语句为:update student u set name= ? , sex = ? where id=?


set主要解决了自动添加标签与处理逗号的问题,另外这种更新方法比较以前的全部更新方式在开发中性能更高。


2.5、choose(when,otherwise) 开关

如果不想用到所有的查询条件,只想选择其中的一个,查询条件有一个满足即可,使用 choose 标签可以解决此类问题,类似于 Java 的 switch 语句。


假定这里需要优先根据编号搜索,没有时选择name,最后考虑sex:

接口:

/**
 * 根据学生编号、姓名和性别获得学生集合
 */
List<Student> selectStudentsByNameAndSex(@Param("id") int id, @Param("name") String name,@Param("sex") String sex);

映射:

SELECT id,name,sex from student
<where>
<choose>
    <when test="id>0">
        id=#{id}
    </when>
    <when test="name!=null and name!=''">
        name=#{name}
    </when>
    <otherwise>
        sex=#{sex}
    </otherwise>
</choose>
</where>

也就是说,这里我们有三个条件,id,name,sex,只能选择一个作为查询条件


如果 id 不为空,那么查询语句为:select * from student where id=?


如果 id 为空,那么看name是否为空,如果不为空,那么语句为 select * from student where name=?;


如果name为空,那么查询语句为 select * from student where sex=?

2.6、trim裁剪

trim标记是一个格式化的标记,可以完成set或者是where标记的功能

①、用 trim 改写上面第二点的 if+where 语句

if+where的办法:

  <select id="selectStudentsByNameAndSex" resultType="student">

        SELECT id,name,sex from student

        <!--1、如果两个if只要有一个有输出就会在sql中添加 where-->
        <where>
            <if test="name!=null and name!=''">
                <!--2、如果where后以and或or开始则会删除and或or-->
                and name like concat(concat('%',#{name}),'%');
            </if>

            <if test="sex!=null and sex!=''">
                and sex=#{sex}
            </if>
        </where>

    </select>

trim的办法:

 <select id="selectStudentsByNameAndSex" resultType="student">

        SELECT id,name,sex from student

        <!--1、prefix表示将前置where,prefixOverrides将删除打头内容-->
        <trim prefix="where" prefixOverrides="and | or">
            <if test="name!=null and name!=''">
                and name like concat(concat('%',#{name}),'%')
            </if>

            <if test="sex!=null and sex!=''">
                and sex=#{sex}
            </if>
        </trim>

    </select>

prefix:将加上前缀

prefixoverride:去掉第一个and或者是or

②、用 trim 改写上面第三点的 if+set 语句

if+set的方法:

  <update id="updateStudent" parameterType="student">
        update student
        <!--自动添加set-->
        <set>
            <!--智能处理逗号问题-->
            <if test="name!=null and name.length()>0">
                name=#{name}
            </if>

            <if test="sex!=null and sex.length()>0">
                sex=#{sex}
            </if>
        </set>
        where id=#{id}
    </update>

trim的方法:

update student

   <trim prefix="set" suffixOverrides=",">
       <if test="name!=null and name.length()>0">
           name=#{name},
       </if>

       <if test="sex!=null and sex.length()>0">
           sex=#{sex},
       </if>
   </trim>

where id=#{id}

suffix:后缀


suffixoverride:去掉最后一个逗号(也可以是其他的标记,就像是上面前缀中的and一样)


可以自定义添加前后缀,与之对应的属性是prefix和suffix。同时通过prefixOverrides和suffixOverrides分别来覆盖首尾部的内容,即忽略不必要的前后缀。就是说它可以充当where标签,也可以充当set标签啦~


目录
相关文章
|
7月前
|
SQL 监控 关系型数据库
一键开启百倍加速!RDS DuckDB 黑科技让SQL查询速度最高提升200倍
RDS MySQL DuckDB分析实例结合事务处理与实时分析能力,显著提升SQL查询性能,最高可达200倍,兼容MySQL语法,无需额外学习成本。
|
7月前
|
SQL 存储 关系型数据库
MySQL体系结构详解:一条SQL查询的旅程
本文深入解析MySQL内部架构,从SQL查询的执行流程到性能优化技巧,涵盖连接建立、查询处理、执行阶段及存储引擎工作机制,帮助开发者理解MySQL运行原理并提升数据库性能。
|
7月前
|
SQL 监控 关系型数据库
SQL优化技巧:让MySQL查询快人一步
本文深入解析了MySQL查询优化的核心技巧,涵盖索引设计、查询重写、分页优化、批量操作、数据类型优化及性能监控等方面,帮助开发者显著提升数据库性能,解决慢查询问题,适用于高并发与大数据场景。
|
8月前
|
SQL XML Java
通过MyBatis的XML配置实现灵活的动态SQL查询
总结而言,通过MyBatis的XML配置实现灵活的动态SQL查询,可以让开发者以声明式的方式构建SQL语句,既保证了SQL操作的灵活性,又简化了代码的复杂度。这种方式可以显著提高数据库操作的效率和代码的可维护性。
496 18
|
6月前
|
SQL 关系型数据库 MySQL
(SQL)SQL语言中的查询语句整理
查询语句在sql中占了挺大一部分篇幅,因为在数据库中使用查询语句的次数远多于更新与删除命令。而查询语句比起其他语句要更加的复杂,可因为sql是数据库不可或缺的一部分,所以即使不懂,也必须得弄懂,以上。
369 0
|
8月前
|
SQL Java 数据库连接
SSM相关问题-1--#{}和${}有什么区别吗?--Mybatis都有哪些动态sql?能简述一下动 态sql的执行原理吗?--Spring支持的几种bean的作用域 Scope
在MyBatis中,`#{}`是预处理占位符,可防止SQL注入,适用于大多数参数传递场景;而`${}`是直接字符串替换,不安全,仅用于动态表名、列名等特殊场景。二者在安全性、性能及使用场景上有显著区别。
335 0
|
8月前
|
SQL 人工智能 数据库
【三桥君】如何正确使用SQL查询语句:避免常见错误?
三桥君解析了SQL查询中的常见错误和正确用法。AI产品专家三桥君通过三个典型案例:1)属性重复比较错误,应使用IN而非AND;2)WHERE子句中非法使用聚合函数的错误,应改用HAVING;3)正确的分组查询示例。三桥君还介绍了学生、课程和选课三个关系模式,并分析了SQL查询中的属性比较、聚合函数使用和分组查询等关键概念。最后通过实战练习帮助读者巩固知识,强调掌握这些技巧对提升数据库查询效率的重要性。
290 0
|
SQL Oracle 关系型数据库
动态sql 和静态sql 上篇
本文讲解基于Oracle高性能动态SQL程序开发。 1.静态SQL与动态SQL: Oracle编译PL/SQL程序块分为两个种: 其一为前期联编(early binding),即SQL语句在程序编译期间就已经确定,大多数的编译情况属于这种类型; 另外一种是后期联编(late binding),即SQL语句只有在运行阶段才能建立,例如当查询条件为用户输入时,那么Oracle的SQL引擎就无法在编译期对该程序语句进行确定,只能在用户输入一定的查询条件后才能提交给SQL引擎进行处理。
1339 0
|
存储 SQL 关系型数据库
动态sql 和静态sql 下篇
1、批量绑定让oracle 在对一组值进行sql操作时绑定一个变量,这一组数据可以是任何的plsql的聚合类型(联合数组,内嵌表,可变数组),集合元素必须是sql的数据类型,比如char date mumber。
1292 0
|
关系型数据库 MySQL 网络安全
5-10Can't connect to MySQL server on 'sh-cynosl-grp-fcs50xoa.sql.tencentcdb.com' (110)")
5-10Can't connect to MySQL server on 'sh-cynosl-grp-fcs50xoa.sql.tencentcdb.com' (110)")
下一篇
开通oss服务