首页 > 数据库 >MyBatis 动态 SQL 最全教程,这样写 SQL 太优雅了!

MyBatis 动态 SQL 最全教程,这样写 SQL 太优雅了!

时间:2024-04-26 10:12:47浏览次数:16  
标签:语句 username mapper 最全 SQL sex sid MyBatis

一、MyBatis动态 sql 是什么

动态 SQL 是 MyBatis 的强大特性之一。在 JDBC 或其它类似的框架中,开发人员通常需要手动拼接 SQL 语句。根据不同的条件拼接 SQL 语句是一件极其痛苦的工作。

例如,拼接时要确保添加了必要的空格,还要注意去掉列表最后一个列名的逗号。而动态 SQL 恰好解决了这一问题,可以根据场景动态的构建查询。

动态SQL(code that is executed dynamically),它一般是根据用户输入或外部条件动态组合的SQL语句块。 动态SQL能灵活的发挥SQL强大的功能、方便的解决一些其它方法难以解决的问题。 相信使用过动态SQL的人都能体会到它带来的便利,然而动态SQL有时候在执行性能 (效率)上面不如静态SQL,而且使用不恰当,往往会在安全方面存在隐患 (SQL 注入式攻击)。

1.Mybatis 动态 sql 是做什么的?

Mybatis 动态 sql 可以让我们在 Xml 映射文件内,以标签的形式编写动态 sql,完成逻辑判断和动态拼接 sql 的功能。

2.Mybatis 的 9 种 动 态 sql 标 签有哪些?

3.动态 sql 的执行原理?

原理为:使用 OGNL 从 sql 参数对象中计算表达式的值,根据表达式的值动态拼接 sql,以此来完成动态 sql 的功能。

推荐一个开源免费的 Spring Boot 实战项目:

https://github.com/javastacks/spring-boot-best-practice

二、MyBatis标签

1.if标签:条件判断

MyBatis if 类似于 Java 中的 if 语句,是 MyBatis 中最常用的判断语句。使用 if 标签可以节省许多拼接 SQL 的工作,把精力集中在 XML 的维护上。

1)不使用动态sql

<select id="selectUserByUsernameAndSex"
        resultType="user" parameterType="com.ys.po.User">
    <!-- 这里和普通的sql 查询语句差不多,对于只有一个参数,后面的 #{id}表示占位符,里面          不一定要写id,
         写啥都可以,但是不要空着,如果有多个参数则必须写pojo类里面的属性 -->
    select * from user where username=#{username} and sex=#{sex}
</select>

if 语句使用方法简单,常常与 test 属性联合使用。语法如下:

<if test="判断条件">    SQL语句</if>

2)使用动态sql

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

以下语句表示为可以按照网站名称(name)或者网址(url)进行模糊查询。如果您不输入名称或网址,则返回所有的网站记录。但是,如果你传递了任意一个参数,它就会返回与给定参数相匹配的记录。

<select id="selectAllWebsite" resultMap="myResult">  
    select id,name,url from website 
    where 1=1    
   <if test="name != null">        
       AND name like #{name}   
   </if>    
   <if test="url!= null">        
       AND url like #{url}    
   </if>
</select>

2.where+if标签

where、if同时使用可以进行查询、模糊查询

注意,<if>失败后, <where> 关键字只会去掉库表字段赋值前面的and,不会去掉语句后面的and关键字,即注意,<where> 只会去掉<if> 语句中的最开始的and关键字。所以下面的形式是不可取的

<select id="findQuery" resultType="Student">
    <include refid="selectvp"/>
    <where>
        <if test="sacc != null">
            sacc like concat('%' #{sacc} '%')
        </if>
        <if test="sname != null">
            AND sname like concat('%' #{sname} '%')
        </if>
        <if test="sex != null">
            AND sex=#{sex}
        </if>
        <if test="phone != null">
            AND phone=#{phone}
        </if>
    </where>
</select>

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

3.set标签

set可以用来修改

<update id="upd">
    update student
    <set>
        <if test="sname != null">sname=#{sname},</if>
        <if test="spwd != null">spwd=#{spwd},</if>
        <if test="sex != null">sex=#{sex},</if>
        <if test="phone != null">phone=#{phone}</if>
    sid=#{sid}
    </set>
    where sid=#{sid}
</update>

4.choose(when,otherwise) 语句

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

<select id="selectUserByChoose" resultType="com.ys.po.User" parameterType="com.ys.po.User">
      select * from user
      <where>
          <choose>
              <when test="id !='' and id != null">
                  id=#{id}
              </when>
              <when test="username !='' and username != null">
                  and username=#{username}
              </when>
              <otherwise>
                  and sex=#{sex}
              </otherwise>
          </choose>
      </where>
  </select>

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

  • 如果 id 不为空,那么查询语句为:select * from user where id=?
  • 如果 id 为空,那么看username 是否为空,如果不为空,那么语句为 select * from user where username=?;
  • 如果 username 为空,那么查询语句为 select * from user where sex=?

5.trim

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

推荐一个开源免费的 Spring Boot 实战项目:

https://github.com/javastacks/spring-boot-best-practice

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

<select id="selectUserByUsernameAndSex" resultType="user" parameterType="com.ys.po.User">
    select * from user
    <!-- <where>
        <if test="username != null">
           username=#{username}
        </if>
         
        <if test="username != null">
           and sex=#{sex}
        </if>
    </where>  -->
    <trim prefix="where" prefixOverrides="and | or">
        <if test="username != null">
           and username=#{username}
        </if>
        <if test="sex != null">
           and sex=#{sex}
        </if>
    </trim>
</select>
  • prefix:前缀
  • prefixoverride:去掉第一个and或者是or

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

<!-- 根据 id 更新 user 表的数据 -->
<update id="updateUserById" parameterType="com.ys.po.User">
    update user u
        <!-- <set>
            <if test="username != null and username != ''">
                u.username = #{username},
            </if>
            <if test="sex != null and sex != ''">
                u.sex = #{sex}
            </if>
        </set> -->
        <trim prefix="set" suffixOverrides=",">
            <if test="username != null and username != ''">
                u.username = #{username},
            </if>
            <if test="sex != null and sex != ''">
                u.sex = #{sex},
            </if>
        </trim>
     
     where id=#{id}
</update>
  • suffix:后缀
  • suffixoverride:去掉最后一个逗号(也可以是其他的标记,就像是上面前缀中的and一样)

③、trim+if同时使用可以添加

<insert id="add">
    insert  into student
    <trim prefix="(" suffix=")" suffixOverrides=",">
        <if test="sname != null">sname,</if>
        <if test="spwd != null">spwd,</if>
        <if test="sex != null">sex,</if>
        <if test="phone != null">phone,</if>
    </trim>

    <trim prefix="values (" suffix=")"  suffixOverrides=",">
        <if test="sname != null">#{sname},</if>
        <if test="spwd != null">#{spwd},</if>
        <if test="sex != null">#{sex},</if>
        <if test="phone != null">#{phone}</if>
    </trim>

</insert>

6.MyBatis foreach标签

foreach是用来对集合的遍历,这个和Java中的功能很类似。通常处理SQL中的in语句。

foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符

你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。

//批量查询
<select id="findAll" resultType="Student" parameterType="Integer">
    <include refid="selectvp"/> WHERE sid in
    <foreach item="ids" collection="array"  open="(" separator="," close=")">
        #{ids}
    </foreach>
</select>
//批量删除
<delete id="del"  parameterType="Integer">
    delete  from  student  where  sid in
    <foreach item="ids" collection="array"  open="(" separator="," close=")">
        #{ids}
    </foreach>
</delete>
整合案例

xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yzx.mapper.StuMapper">
    <sql id="selectvp">
        select  *  from  student
    </sql>
    
    <select id="find" resultType="Student">
        <include refid="selectvp"/>
    </select>

    <select id="findbyid"  resultType="student">
        <include refid="selectvp"/>
        WHERE 1=1
        <if test="sid != null">
            AND sid like #{sid}
        </if>
    </select>

        <select id="findQuery" resultType="Student">
            <include refid="selectvp"/>
            <where>
                <if test="sacc != null">
                    sacc like concat('%' #{sacc} '%')
                </if>
                <if test="sname != null">
                    AND sname like concat('%' #{sname} '%')
                </if>
                <if test="sex != null">
                    AND sex=#{sex}
                </if>
                <if test="phone != null">
                    AND phone=#{phone}
                </if>
            </where>
        </select>

    <update id="upd">
        update student
        <set>
            <if test="sname != null">sname=#{sname},</if>
            <if test="spwd != null">spwd=#{spwd},</if>
            <if test="sex != null">sex=#{sex},</if>
            <if test="phone != null">phone=#{phone}</if>
        sid=#{sid}
        </set>
        where sid=#{sid}
    </update>

    <insert id="add">
        insert  into student
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="sname != null">sname,</if>
            <if test="spwd != null">spwd,</if>
            <if test="sex != null">sex,</if>
            <if test="phone != null">phone,</if>
        </trim>

        <trim prefix="values (" suffix=")"  suffixOverrides=",">
            <if test="sname != null">#{sname},</if>
            <if test="spwd != null">#{spwd},</if>
            <if test="sex != null">#{sex},</if>
            <if test="phone != null">#{phone}</if>
        </trim>

    </insert>
    <select id="findAll" resultType="Student" parameterType="Integer">
        <include refid="selectvp"/> WHERE sid in
        <foreach item="ids" collection="array"  open="(" separator="," close=")">
            #{ids}
        </foreach>
    </select>

    <delete id="del"  parameterType="Integer">
        delete  from  student  where  sid in
        <foreach item="ids" collection="array"  open="(" separator="," close=")">
            #{ids}
        </foreach>
    </delete>



</mapper>

测试类:

package com.yzx.test;

import com.yzx.entity.Student;
import com.yzx.mapper.StuMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class StuTest {
    SqlSession sqlSession=null;
    InputStream is=null;

    @Before
    public   void  before() throws IOException {
        //1.读取核心配置文件
        is= Resources.getResourceAsStream("sqlMapperConfig.xml");
        //2.拿到工厂构建类
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder=new SqlSessionFactoryBuilder();
        //3.拿到具体工厂
        SqlSessionFactory build=sqlSessionFactoryBuilder.build(is);
        //4.拿到session
        sqlSession = build.openSession();
    }

    @After
    public  void  after(){
        //7,提交事务
        sqlSession.commit();
        //8.关闭资源
        sqlSession.close();
        if(is!=null){
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        };
    }

    //查询所有
    @Test
    public  void  find(){
        //5.获取具体的mapper接口
        StuMapper mapper=sqlSession.getMapper(StuMapper.class);
        //6.调用执行
        List<Student> list=mapper.find();
        list.forEach(a-> System.out.println(a));
    }
    //查询单个
    @Test
    public  void  findbyid(){

        StuMapper mapper=sqlSession.getMapper(StuMapper.class);
        List<Student> list=mapper.findbyid(2);
        list.forEach(a-> System.out.println(a));
    }
    //模糊查询
    @Test
    public  void  findQuery(){

        StuMapper mapper=sqlSession.getMapper(StuMapper.class);

        Student  stu=new Student();
        stu.setSname("小");
        stu.setSex("男");
        List<Student> list=mapper.findQuery(stu);
        list.forEach(a-> System.out.println(a));
    }
    //修改
    @Test
    public  void  upd(){

        StuMapper mapper=sqlSession.getMapper(StuMapper.class);

        Student  stu=new Student();
        stu.setSid(3);
        stu.setSname("小若");
        stu.setSex("人妖");
        int i=mapper.upd(stu);
        System.out.println("修改了"+i+"条数据"+"  "+stu.toString());

    }
    //添加
    @Test
    public  void  add(){

        StuMapper mapper=sqlSession.getMapper(StuMapper.class);

        Student  stu=new Student();
        stu.setSname("小贺");
        stu.setSex("男");
        stu.setPhone("99999999");
        int i=mapper.add(stu);
        System.out.println("添加了"+i+"条数据"+"  "+stu.toString());

    }

    //批量操作
    @Test
    public  void  findAll(){

        StuMapper mapper=sqlSession.getMapper(StuMapper.class);
        Integer[] i={1,2,3,4};
        List<Student> list=mapper.findAll(i);
        list.forEach(a-> System.out.println(a));
    }
    //批量操作

    //批量删除
    @Test
    public  void  del(){
        StuMapper mapper=sqlSession.getMapper(StuMapper.class);
        Integer[] i={1,2,3,4};
        int i1=mapper.del(i);
        System.out.println("删除了"+i1+"条数据");
    }
}

7.sql

在实际开发中会遇到许多相同的SQL,比如根据某个条件筛选,这个筛选很多地方都能用到,我们可以将其抽取出来成为一个公用的部分,这样修改也方便,一旦出现了错误,只需要改这一处便能处处生效了,此时就用到了<sql>这个标签了。

当多种类型的查询语句的查询字段或者查询条件相同时,可以将其定义为常量,方便调用。为求<select>结构清晰也可将 sql 语句分解。

<sql id="selectvp">
    select  *  from  student
</sql>

8.include

这个标签和<sql>是天仙配,是共生的,include用于引用sql标签定义的常量。比如引用上面sql标签定义的常量

refid这个属性就是指定<sql>标签中的id值(唯一标识)

<select id="findbyid"  resultType="student">
    <include refid="selectvp"/>
    WHERE 1=1
    <if test="sid != null">
        AND sid like #{sid}
    </if>
</select>

9.如何引用其他XML中的SQL片段

比如你在com.xxx.dao.xxMapper这个Mapper的XML中定义了一个SQL片段如下:

<sql id="Base_Column_List"> ID,MAJOR,BIRTHDAY,AGE,NAME,HOBBY</sql>

此时我在com.xxx.dao.PatinetMapper中的XML文件中需要引用,如下:

<include refid="com.xxx.dao.xxMapper.Base_Column_List"></include>

三、MyBatis关联查询

1.MyBatis一对多关联查询

<!--一对多-->
<resultMap id="myStudent1" type="student1">
    <id property="sid" column="sid"/>
    <result property="sname" column="sname"/>
    <result property="sex" column="sex"/>
    <result property="sage" column="sage"/>
    <collection property="list" ofType="teacher">
        <id property="tid" column="tid"/>
        <result property="tname" column="tname"/>
        <result property="tage" column="tage"/>
    </collection>
</resultMap>

<!--一对多-->
<select id="find1" resultMap="myStudent1">
    select  *  from  student1  s  left  join  teacher  t  on s.sid=t.sid
</select>

2.MyBatis多对一关联查询

<!--多对一-->
<resultMap id="myTeacher" type="teacher">
    <id property="tid" column="tid"/>
    <result property="tname" column="tname"/>
    <result property="tage" column="tage"/>
    <association property="student1" javaType="Student1">
        <id property="sid" column="sid"/>
        <result property="sname" column="sname"/>
        <result property="sex" column="sex"/>
        <result property="sage" column="sage"/>
    </association>
</resultMap>


<!--多对一-->
<select id="find2" resultMap="myTeacher">
select  *  from  teacher  t right join student1 s on  t.sid=s.sid
</select>

3.MyBatis多对多关联查询

<!--多对多 以谁为主表查询的时候,主表约等于1的一方,另一方相当于多的一方-->
<select id="find3" resultMap="myStudent1">
    select  *  from  student1 s  left join relevance r on  s.sid=r.sid  left join teacher t on  r.tid=t.tid
</select>

版权声明:本文为CSDN博主「变成秃头怪」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/SGLP521/article/details/121509714

更多文章推荐:

1.Spring Boot 3.x 教程,太全了!

2.2,000+ 道 Java面试题及答案整理(2024最新版)

3.免费获取 IDEA 激活码的 7 种方式(2024最新版)

觉得不错,别忘了随手点赞+转发哦!

标签:语句,username,mapper,最全,SQL,sex,sid,MyBatis
From: https://www.cnblogs.com/javastack/p/18159350

相关文章

  • 【Qt 专栏】Qt:SQLite数据库操作示例
    转载自:https://blog.csdn.net/qq_40344790/article/details/129521573作者:DevFrank(CSDNC/C++ 优质创作者)1. sqlite介绍SQLite 是一种轻量级的嵌入式关系型数据库管理系统,它是一个开源的、零配置的、自包含的、事务性的SQL数据库引擎。SQLite的设计目标是简单、高效、可......
  • SQL Server实战二:创建、修改、复制、删除数据库表并加以数据处理
      本文介绍基于MicrosoftSQLServer软件,实现数据库表的创建、修改、复制、删除与表数据处理的方法。目录1交互式创建数据库表T2交互式创建数据库表S3T-SQL创建数据库表C4T-SQL创建数据库表SC5T-SQL创建数据库表TC6交互式向数据库表S中添加新列NATIVE7交互式修改数据库......
  • 2023最新!MySQL8于win10环境下的安装配置保姆级教程
    2023最新!MySQL8于win10环境下的安装配置保姆级教程MySQL官网:https://www.mysql.com/downloads/导航目录2023最新!MySQL8于win10环境下的安装配置保姆级教程导航一、MySQL下载二、安装MySQLchoosingaSetupTypeselectproductsdownloadselectfeaturestoinstallInstallation......
  • SQL SERVER中的字符类型使用Unicode
    字符编码和排序规则下面的讨论用到W、王和......
  • MySQL—MySQL的存储引擎之InnoDB
    MySQL—MySQL的存储引擎之InnoDB存储引擎及种类存储引擎说明MyISAM高速引擎,拥有较高的插入,查询速度,但不支持事务InnoDB5.5版本后MySQL的默认数据库存储引擎,支持事务和行级锁,比MyISAM处理速度稍慢ISAMMyISAM的前身,MySQL5.0以后不再默认安装MRG_MyISAM将多......
  • 36.mybatis-plus代码自动生成器
    很重要的功能:参考官网:https://baomidou.com/pages/779a6e/#快速入门mybatis-plus自动帮你生成pojocontroller.....东西没啥废话上代码这个依赖: <dependency><groupId>org.apache.velocity</groupId><artifactId>velocity-engine-core</artifa......
  • FLINKCDC 3.0整库同步MYSQL至DORIS(FLINK1.18): 历程
    大数据技术涉及组件较多,各个环境较DEMO又不尽相同,所以参照DEMO进行,任然很多报错信息出现。如下报错处理,尽供参考:1.创建同步配置文件################################################################################Description:SyncMySQLalltablestoDoris#########......
  • 35.mybatis-plus简单整理
    这个可得好好介绍一下了但很多开源项目都还是采用的ssm中的mybatis但这个就是对mybatis的优化优化又优化既然语法优化简便了那自然就有其语法等规范参考:官网https://baomidou.com/pages/2976a3/#spring-boot首先肯定是依赖啦啦啦我的对应springboot版本为2.2.5.RELEASE......
  • springboot+mybatisplus+dynicDatasource 从数据库表中查询数据源 动态添加
    1、pom依赖<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.12</version><relativePath/><!--lookuppa......
  • 记录MySQL分页数据重复问题
    1、准备数据2、sql查询1、查询第一页的结果select*fromtestlimit0,3;2、查询第二页的结果select*fromtestlimit1,3;3、查询第三页的结果select*fromtestlimit2,3;3、结果由上图所示,每次分页都有重复数产生4、原因我们知道orderby排序的时......