MyBatis中动态SQL的使用和注意事项说明

news2024/11/25 6:54:23

文章目录

  • 0、前言
  • 1、if
  • 2、where
  • 3、trim
  • 4、choose-when-otherwise
  • 5、foreach
    • 应用场景1: 通过数组实现批量删除
    • 应用场景2: 通过list集合实现批量添加
  • 6、include抽取公共SQL片段

0、前言

MyBatis框架动态SQL技术是根据特定的条件拼接SQL语句的功能,存在的意义是为了解决拼接SQL语句字符串痛点问题。

对于动态SQL不是什么新的东西,我们之前写的SQL是直接写死在xml配置文件中的,对于很多的代码判断,我们需要利用SQL的一些函数来进行判断,比如说判断age不能为空就需要在where语句中加上age is not null

那我们能不能在sql层面,加入一些逻辑代码,根据不同的条件生成不同的sql语句。是可以的。

其中包括,if判断,是否需要当前的SQL片段, where/trim/choose/foreach/sql片段include等等。

1、if

if标签可通过test属性的表达式进行判断,若表达式的结果为true,则标签中的内容会执行;反之标签中的内容不会执行
应用的场景:主要是多条件的查询
下面通过例子来说明:对于MyBatis项目搭建不太会的,直接看博文从0到1搭建MyBatis实例思路剖析,跟着做完就能入门MyBatis。
如果我想是以下这种情况的查询,就是一种多条件查询

对于这种多条件查询,如果没有动态SQL的处理逻辑是:
直接在SQL进行判断,或者是,直接在代码中处理。

select * from table where (userid = #{userid} or @userid is null) and (birth = #{birth} or birth = null”) and .....

或者是

if(userid != null || userid != ''){
	userMapper.select(id)
}
... 

对于动态SQL可以很好的解决这个问题:
首先定义DynamicSqlMapper接口

public interface DynamicSQLMapper {
    /**
     * 多条件查询
     */
    List<Emp> getEmpByCondition(Emp emp);
}

DynamicSqlMapper.xml

   <!--        List<Emp> getEmpByCondition(Emp emp);-->
    <!--    加上1=1使得:即使emp_name为空,也不会导致sql语句变成:where and xxx-->
    <select id="getEmpByCondition" resultType="Emp">
        select * from t_emp where 1=1
        <if test="empName != null and empName != ''">
            and emo_name = #{empName}
        </if>
        <if test="age != null and age != ''">
            and age = #{age}
        </if>
        <if test="email != null and email != ''">
            and email = #{email}
        </if>
        <if test="sex != null and sex != ''">
            and sex = #{sex}
        </if>
    </select>

测试类:

 /**
     * 动态sql
     * 1: if: 根据标签中test属性所对应的内容决定标签中的内容是否拼接在sql语句中
     */
    @Test
    public void testGetEmpByCondition() throws IOException {
        SqlSession sqlSession = getSqlSession();
        DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
        // 各信息都不为null/空字符串
        List<Emp> emp1 = mapper.getEmpByCondition(new Emp(null, "lucy", 23, "0", "lucy@gmail.com", null));
        // 中间存在查询出来是空,可能导致"select * from t_emp where emp_name= ? and and sex = ?..."的and和and在一起的情况
        List<Emp> emp2 = mapper.getEmpByCondition(new Emp(null, "", null, "1", "", null));
        // 第一个查询条件为空字符串,可能导致"select * from t_emp where and age = ? and ..."的where和and在一起的情况
        List<Emp> emp3 = mapper.getEmpByCondition(new Emp(null, null, null, "0", null, null));
        System.out.println(emp1);
        System.out.println(emp2);
        System.out.println(emp3);
    }

在这里插入图片描述

2、where

用于替代SQL语句中的where出现的,通过观察发现,对于只使用if来对是否要拼接条件进行判断,可能出现的情况是如果所有的if都不满足。那么最后生成的SQL会变成

select * from t_emp where 

这必定报错,所以,需要加上一个 1 = 1,让其不能报错。能不能把where也加上一个判断。<where>应运而生,
当where中的所有条件都不成立,在生成最终SQL的时候,就不会加上where
应用场景:多条件查询
使用方法是直接替代where

   <!--        List<Emp> getEmpByCondition(Emp emp);-->
    <!--    加上1=1使得:即使emp_name为空,也不会导致sql语句变成:where and xxx-->
    <select id="getEmpByCondition" resultType="Emp">
        select * from t_emp
        <where>
            <if test="empName != null and empName != ''">
                and emo_name = #{empName}
            </if>
            <if test="age != null and age != ''">
                and age = #{age}
            </if>
            <if test="email != null and email != ''">
                and email = #{email}
            </if>
            <if test="sex != null and sex != ''">
                and sex = #{sex}
            </if>
        </where>
    </select>

测试类和if的一样,这里就不在重复。

3、trim

trim标签是自己自动的加上前缀和后缀,或者是去除掉前缀和后缀。
有四个属性;

prefix,prefixOverrides,suffix,suffixOverrides
  • prefix:给sql语句拼接的前缀
  • suffix:给sql语句拼接的后缀
  • prefixOverrides:去除sql语句前面的关键字或者字符,该关键字或者字符由prefixOverrides属性指定,假设该属性指定为"AND",当sql语句的开头为"AND",trim标签将会去除该"AND"
  • suffixOverrides:去除sql语句后面的关键字或者字符,该关键字或者字符由suffixOverrides属性指定
 <select id="getEmpByCondition" resultType="Emp">
        select * from t_emp
        <trim prefix="where" suffixOverrides="or|and" prefixOverrides="or|and">
            <if test="empName != null and empName != ''">
                and emo_name = #{empName}
            </if>
            <if test="age != null and age != ''">
                and age = #{age}
            </if>
            <if test="email != null and email != ''">
                and email = #{email}
            </if>
            <if test="sex != null and sex != ''">
                and sex = #{sex}
            </if>
        </trim>
    </select>

去除掉最后的and或者是or,加上where的前缀。 如果为空,则直接不输出标签内的内容。

4、choose-when-otherwise

choosewhenotherwise相当于if…else if…else

<!--        List<Emp> getEmpByChoose(Emp emp);-->
    <select id="getEmpByChoose" resultType="Emp">
        select * from t_emp
        <where>
            <choose>
                <when test="empName != null and empName != ''">
                    emo_name = #{empName}
                </when>
                <when test="age != null and age != ''">
                    age = #{age}
                </when>
                <when test="sex != null and sex != ''">
                    sex = #{sex}
                </when>
                <when test="email != null and email != ''">
                    email = #{email}
                </when>
                <otherwise>
                    did = 2
                </otherwise>
            </choose>
        </where>
    </select>

5、foreach

应用场景1: 通过数组实现批量删除

我们知道,如果要写批量删除的SQL有两种方式,一种是
delete from table where id in (1,2,3) 或者是delete from table where id = 1 or id = 2 or id = 3
对于foreach的使用也有两种形式:
DynamicSqlMapper接口:

public interface DynamicSQLMapper {
    /**
     * 通过数组实现批量删除
     */
    int deleteMoreByArray(@Param("eids") Integer[] eids);
}

DynamicSqlMapper.xml
方法一:delete from table where id in (1,2,3) 的形式

<!--        int deleteMoreByArray(Integer[] eids);-->
<!--    没加@Param时,
        报错:Parameter 'eids' not found. Available parameters are [array, arg0]
        因此最好都加上@Param-->
<!--        int deleteMoreByArray(@Param("eids") Integer[] eids);-->
    <delete id="deleteMoreByArray">
        delete from t_emp where eid in
            <foreach collection="eids" item="eid" separator="," open="(" close=")">
                #{eid}
    		</foreach>
    </delete>

方法二:delete from table where id = 1 or id = 2 or id = 3的形式

<!--        int deleteMoreByArray(Integer[] eids);-->
    <delete id="deleteMoreByArray">
    <!--方法2:-->
        delete from t_emp where
        <foreach collection="eids"  item="eid" separator="or">
            eid = #{eid}
        </foreach>
    </delete>

测试类;

 @Test
    public void testDeleteMoreByArray() throws IOException {
        SqlSession sqlSession = getSqlSession();
        DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
        int result = mapper.deleteMoreByArray(new Integer[]{2,3});
        System.out.println(result);
    }

在这里插入图片描述

应用场景2: 通过list集合实现批量添加

DynamicSqlMapper接口

public interface DynamicSQLMapper {
    /**
     * 通过list集合实现批量添加
     */
    int insertMoreByList(@Param("emps") List<Emp> emps);
}

DynamicSqlMapper.xml

<!--        int insertMoreByList(List<Emp> emps);-->
<!--    不加注解会报错:Parameter 'emps' not found. Available parameters are [arg0, collection, list]-->
<!--    int insertMoreByList(@Param("emps") List<Emp> emps);-->
    <insert id="insertMoreByList">
        insert into t_emp values
        <foreach collection="emps" item="emp" separator=",">
            (#{emp.eid}, #{emp.empName}, #{emp.age}, #{emp.sex}, #{emp.email}, null)
        </foreach>
    </insert>

测试类:

 /**
     * 5、foreach
     *      collection  需要循环的数组或集合
     *      item        表示数组或集合中的每一个数据
     *      separator   循环体之间的分隔符
     *      open        foreach标签所循环的所有内容的开始符
     *      close       foreach标签所循环的所有内容的结束符
     */
 @Test
    public void testInsertMoreByList() throws IOException {
        SqlSession sqlSession = getSqlSession();
        DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
        Emp emp1 = new Emp(100, "fckey", 23, "0", "lucy@gmail.com", null);
        Emp emp2 = new Emp(101, "fckey", 23, "0", "lucy@gmail.com", null);
        Emp emp3 = new Emp(102, "lucy", 23, "0", "lucy@gmail.com", null);
        List<Emp> emps = Arrays.asList(emp1, emp2, emp3);
        System.out.println(mapper.insertMoreByList(emps));
    }

在这里插入图片描述

6、include抽取公共SQL片段

mapper.xml中有些sql片段,在多个sql语句中都有用,每个都写的话显得代码冗余,可以用到代码片段,将公共部分抽取出来
注意点:

  1. 最好基于单表定义sql片段
  2. sql片段中不要存在where标签,因为where标签会自动优化sql中的and和or
  3. 尽量存放是简单的if标签
        重点1:使用sql标签,定义自定义id,将工共sql片段抽取出来
        <sql id="choose-when-id-name">
            <choose>
                <when test="id!=null">id=#{id}</when>
                <when test="name!=null">name=#{name}</when>
            </choose>
        </sql>
        <update id="updatePwd">
            update public."user"
            <set>
                <if test="name !=null">name=#{name},</if>
                <if test="pwd !=null">pwd=#{pwd},</if>
            </set>
            <where>
                重点2:使用include标签和refid标签来进行sql片段的引入
               <include refid="choose-when-id-name"></include>
            </where>
        </update>

notice: 这里的set标签是用来替代update 中的set的。可以理解为是具有判断功能的set字段。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/552383.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【计算机图形学】曲线和曲面

模块5 曲线和曲面 一 实验目的 编写曲线和曲面的算法 二 实验内容 1&#xff1a;绘制Bezier曲线&#xff0c;并采用自行设计输入和交互修改数据点的方式。 实验结果如下图所示&#xff1a; 第一步&#xff1a;输入特征多边形的顶点个数&#xff0c;并按照顺序输入顶点的坐…

《心静的力量》读书笔记

让心静下来&#xff0c;战胜一切忧虑 于我们每个人而言&#xff0c;最重要的就是不要去看远方模糊不清的事&#xff0c;而要做手边真实清楚的事。 明天的重担&#xff0c;加上昨天的重担&#xff0c;会成为今天的最大障碍&#xff0c;要把未来同过去一样紧紧地关在门外……未…

将MetaHuman的身体替换为虚幻商城模型的身体

一、准备好MetaHuman模型和虚幻商城模型 1.准备好MetaHuman模型,参考这篇文章 虚幻商城模型转MetaHuman制作MetaHuman并导入UE,同时复制一个MetaHuman模型 2.下载虚幻商城的原始模型,并导入UE 二、将虚幻商城模型的头去掉 1.打开虚幻商城的模型,找到分段 2.在右边点击…

chatgpt赋能Python-pythonapp开发

PythonApp开发&#xff1a;为什么选择Python实现&#xff1f; Python是当今最流行的编程语言之一&#xff0c;尤其在Web应用开发和数据分析领域更是大有作为。本文将探讨Python在App开发领域中的表现&#xff0c;为什么Python可以成为您理想的选择&#xff1f; 1. 简单易学 …

深度学习基础入门篇[8]::计算机视觉与卷积神经网络、卷积模型CNN综述、池化讲解、CNN参数计算

【深度学习入门到进阶】必看系列&#xff0c;含激活函数、优化策略、损失函数、模型调优、归一化算法、卷积模型、序列模型、预训练模型、对抗神经网络等 专栏详细介绍&#xff1a;【深度学习入门到进阶】必看系列&#xff0c;含激活函数、优化策略、损失函数、模型调优、归一化…

leetcode--优先队列

2163,删除元素后的最小差值 给你一个下标从 0 开始的整数数组 nums &#xff0c;它包含 3 * n 个元素。 你可以从 nums 中删除 恰好 n 个元素&#xff0c;剩下的 2 * n 个元素将会被分成两个 相同大小 的部分。 前面 n 个元素属于第一部分&#xff0c;它们的和记为 sumfirst …

RabbitMQ如何保证顺序性

1. RabbitMQ消息顺序性说明 顺序性&#xff1a; 消息的顺序性是指消费者消费到消息和发送者发布的消息的顺序是一致的 举个例子&#xff0c;不考虑消息重复的情况下&#xff0c;如果生产者发布的消息分别为msg1、msg2、msg3 那么消费者必然也是按照 msg1、msg2、msg3 的顺序来…

【数据结构】--- 博主拍了拍你并向你扔了一“堆”二叉树(堆的概念+结构+代码实现)

文章目录 前言&#x1f31f;一、二叉树的顺序结构及实现&#xff1a;&#x1f31f;二、堆的概念及结构&#xff1a;&#x1f31f;三、堆的代码实现&#xff1a;&#x1f30f;3.1 堆的创建&#xff1a;&#x1f30f;3.2 堆的结构&#xff1a;&#x1f30f;3.3 初始化&#xff1a…

Spring Security 如何实现身份认证和授权?

Spring Security 是一个开源的安全框架&#xff0c;提供了基于权限的访问控制、身份认证、安全性事件发布等功能。在 Spring Boot 应用中使用 Spring Security 可以非常方便地实现用户身份认证和授权。 Spring Security 实现身份认证的主要方式是使用认证过滤器链&#xff0c;…

C语言入门级小游戏——扫雷

文章目录 游戏思路游戏文件的创建游戏菜单棋盘的创建初始化棋盘打印棋盘 布置雷排查雷game.h —— 游戏函数的声明game.c —— 游戏函数的实现test.c —— 游戏的测试 今天我们写一个小游戏——扫雷来增加我们对编程的兴趣 希望这篇文章对友友们有帮助! 游戏思路 游戏文件的创…

Linux:iptables防火墙(SNAT和DNAT)

Linux&#xff1a;iptables防火墙 一、SNAT策略及应用1.1 SNAT原理1.2 SNAT应用 二、DNAT策略及应用2.1 DNAT原理2.2 DNAT应用 一、SNAT策略及应用 1.1 SNAT原理 SNAT 应用环境&#xff1a;局域网主机共享单个公网IP地址接入Internet&#xff08;私有不能在Internet中正常路由…

MySQL数据库笔记——进阶篇

文章目录 存储引擎MySQL体系结构存储引擎简介InnoDB介绍MyISAMMemory 存储引擎的选择小结 索引概述索引结构概述BtreeBTreeHash 存储引擎 MySQL体系结构 连接层&#xff1a; 最上层是一些客户端和链接服务&#xff0c;主要完成一些类似于连接处理、授权认证、及相关的安全方案…

《计算机网络—自顶向下方法》 Wireshark实验(十):NAT 协议分析

NAT&#xff08;Network Address Translation&#xff09;网络地址转换&#xff0c;即在私有地址和全局地址之间转换的协议。私有地址是不能用在 Internet 上(路由器将丢弃寻址这种地址的包)的内部地址。这些地址是不能够在公网上面用的&#xff0c;只能用在局域网的内部。私有…

win安装Nodejs

文章目录 1、安装环境2、安装步骤3、更换npm源为淘宝镜像4、更多node版本下载 1、安装环境 node.js下载官网: nodejs官网 点击选中图标下载即可&#xff1a; 2、安装步骤 1、双击安装包&#xff0c;一直点击next 2、点击change按钮&#xff0c;更换到自己的指定安装位置&…

基于fpga的图像处理之3x3_5x5算子模板中值排序

本文的思路框架&#xff1a; ①本文介绍3x3算子模块和5x5算子模块中&#xff0c;矩阵转化成串行数据后&#xff0c;对其排序&#xff0c;并获取矩阵中值数据&#xff1b; ②本例程中采用的FPGA设计技巧&#xff0c;可用于借鉴&#xff0c;一是采用for循环实现串行数据转化并行数…

vite创建vue2项目

使用vite首先需要注意官方给出的兼容性注意 Vite 需要 Node.js 版本 14.18&#xff0c;16。然而&#xff0c;有些模板需要依赖更高的 Node 版本才能正常运行&#xff0c;当你的包管理器发出警告时&#xff0c;请注意升级你的 Node 版本。 1.初始化vite项目 输入以下命令&#…

Spring MVC 是什么?与 Struts 的区别是什么?

Spring MVC是Spring框架中的一个模块&#xff0c;它提供了一种基于MVC&#xff08;Model-View-Controller&#xff09;架构的Web开发方式。与传统的JSP/Servlet开发方式相比&#xff0c;Spring MVC更加灵活、高效&#xff0c;可以帮助开发人员快速构建高质量的Web应用程序。本文…

vue diff算法与虚拟dom知识整理(10) 梳理patch处理相同节点比较的基本逻辑

这次 我们来讲 diff算法处理到 当新旧节点 是同一个节点时的处理 我们之前也说过 如果不是同一个节点 他就会暴力拆旧 把新的插上去 但当他们是同一个节点 需要精细化比较 最做小化更新 这块我们还没有处理 打开我们的案例 打开 patch.js 对应其实就还是这一块还没有写 我们…

PostgreSQL查询引擎——transform expressions之AEXPR_OP

static Node *transformAExprOp(ParseState *pstate, A_Expr *a){Node *lexpr a->lexpr; Node *rexpr a->rexpr; // 操作符左右表达式Node *result;/* Special-case "foo NULL" and "NULL foo" for compatibility with standards-broke…

Bug——后端返回LocalDateTime类型数据中间出现一个T

错误如下图所示: 返回的JSON格式数据里面会有一个多出来的T. 解决方案&#xff1a; 在后端的POJO层的实体类的LocalDateTime属性上面加上一个注解 JsonFormat(pattern"yyyy-MM-dd HH:mm:ss") 如下所示&#xff0c;然后在返回JSON格式数据时就不会出现那个多余的T了…