mybatis实现动态sql

news2025/1/18 17:13:41

第一章、动态SQL

MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦。例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。

例如,下面需求就会使用到拼接sql语句:

【需求】:查询男性用户,如果输入了用户名,按用户名模糊查询,如果没有输入用户名,就查询所有男性用户

正常的sql语句:查询男性并且用户名中包含zhang

在这里插入图片描述

select * from tb_user where sex = "男" and user_name like '%zhang%'

在这里插入图片描述

select * from tb_user where  sex = "男"  

​ 实现需求时还要判断用户是否输入用户名来做不同的查询要求,而这里似乎没有办法判断是否输入了用户名,因此可以考虑使用动态sql来完成这个功能。

​ 动态 SQL 元素和后面学习的 JSTL 或基于之前学习的类似 XML 的文本处理器相似。在 MyBatis 之前的版本中,有很多元素需要花时间了解。MyBatis 3 开始精简了元素种类,现在只需学习原来一半的元素便可。MyBatis 采用功能强大的 OGNL 的表达式来淘汰其它大部分元素。

常见标签如下:

if:判断   if(1 gt 2){}
choose (when, otherwise):分支判断    switch:多选一
trim (where, set):去除
foreach:循环遍历标签

动态SQL中的业务逻辑判断需要使用到以下运算符: ognl表达式

1.   e1 or e2 满足一个即可
2.   e1 and e2 都得满足 
3.    e1 == e2,e1 eq e2 判断是否相等
4.    e1 != e2,e1 neq e2 不相等
5.    e1 lt e2:小于   lt表示less than 
6.    e1 lte e2:小于等于,其他gt(大于),gte(大于等于) gt 表示greater than
7.    e1 in e2 
8.    e1 not in e2
9.    e1 + e2,e1 * e2,e1/e2,e1 - e2,e1%e2
10.   !e,not e:非,求反
11.   e.method(args)调用对象方法
12.   e.property对象属性值
13.   e1[ e2 ]按索引取值,List,数组和Map
14.   @class@method(args)调用类的静态方法
15.   @class@field调用类的静态字段值

1、if标签

格式:

 <if test="判断条件">
   满足条件执行的代码
 </if>
说明:
 1)if标签:判断语句,用于进行逻辑判断的。如果判断条件为true,则执行if标签的文本内容
 2)test属性:用来编写表达式,支持ognl;

【需求】:查询男性用户,如果输入了用户名,按用户名模糊查询,如果没有输入用户名,就查询所有男性用户

正常的sql语句:查询男性并且用户名中包含zhang

在这里插入图片描述

select * from tb_user where sex = "男" and user_name like '%zhang%'

在这里插入图片描述

select * from tb_user where  sex = "男"  

​ 实现需求时还要判断用户是否输入用户名来做不同的查询要求,而这里似乎没有办法判断是否输入了用户名,因此可以考虑使用动态sql来完成这个功能。

​ 上述动态sql语句部分: and user_name like ‘%zhang%’

1.1、定义接口方法

​ 在UserMapper接口中,定义如下方法:

   /**
     * 根据用户名模糊查询
     * @param userName
     * @return
     */
    List<User> queryLikeUserName(@Param("userName") String userName);
1.2、编写SQL

​ 在UserMapper.xml文件中编写与方法名同名的sql语句:

  <select id="queryLikeUserName" resultType="user">
       select * from user where sex='男'
       <if test="userName!=null and userName.trim()!=''">
           and username like '%${userName}%'
       </if>
   </select>

【注】<if> 判断中:

1、if标签:用来判断;

2、test属性:使用OGNL表达式,完成具体的判断业务逻辑;

3、这里使用的字符串拼接,所以这里不能是#取值,只能使用$取值,否则会报错

1.3、测试

【userName有值】

在这里插入图片描述

对应的SQL语句是:select * from user where sex=“男” and username like ‘%孙%’

【userName没有值】

在这里插入图片描述

对应的SQL语句是:select * from user where sex=“男”

【小结】

1、if标签:用来在sql中处理判断是否成立的情况;
2、属性:test中书写OGNL表达式,如果结果为true,if标签的文本中的内容会被拼接到SQL中,反之不会被拼接到SQL中;
3、if标签的应用场景:适用于 二选一 

2、choose,when,otherwise

choose标签:分支选择(多选一,遇到成立的条件即停止)
	when子标签:编写条件,不管有多少个when条件,一旦其中一个条件成立,后面的when条件都不执行。
           test属性:编写ognl表达式
	otherwise子标签:当所有条件都不满足时,才会执行该条件。

需求:

编写一个查询方法,设置两个参数,一个是用户名,一个是住址。

根据用户名或者住址查询所有男性用户:
	如果输入了用户名则按照用户名模糊查找,
	否则就按照住址查找,两个条件只能成立一个,
	如果都不输入就查找用户名为“孙悟空”的用户。

【需求分析】

1、查询所有男性用户,如果输入了用户名则按照用户名模糊查找;

SELECT * FROM  user WHERE  sex = "男" AND  username LIKE  '%孙%';

2、查询所有男性用户,如果输入了住址则按照住址查询;

SELECT * FROM  user WHERE  sex = "男" AND  address = "花果山水帘洞";

3、查询所有男性用户,如果都不输入就查找用户名为“孙悟空”的用户。

SELECT * FROM  user WHERE  sex = "男" AND username = '孙悟空';
2.1、定义接口方法

在UserMapper接口中,定义接口方法:

 /*
    查询用户名或者地址
  */
 List<User> queryByUserNameOrAddress(@Param("userName") String userName, @Param("address") String address);
2.2、编写SQL

在UserMapper.xml中编写对应的SQL语句

<!--
        根据用户名或者住址查询所有男性用户:
            如果输入了用户名则按照用户名模糊查找,
            否则就按照住址查找,两个条件只能成立一个,
            如果都不输入就查找用户名为“孙悟空”的用户。
  -->
    <select id="queryByUserNameOrAddress" resultType="user">
        select * from user where sex='男'
        <choose>
            <when test="userName!=null and userName.trim()!=''">
                and username like '%${userName}%'
            </when>
            <when test="address!=null and address.trim()!=''">
                and address = #{address}
            </when>
            <otherwise>
                and username='孙悟空'
            </otherwise>
        </choose>
    </select>
2.3、测试

编写测试类,对这个方法进行测试:

@Test
public void queryByUserNameOrAddress(){
    List<User> userList = userMapper.queryByUserNameOrAddress("", null);
    System.out.println("userList = " + userList);
}

【小结】

1、choose,when,otherwise标签组合的作用类似于java中的switch语句,使用于多选一;

3、where

where标签:拼接多条件查询时 1、能够添加where关键字; 2、能够去除多余的and或者or关键字

案例:按照如下条件查询所有用户,

如果输入了用户名按照用户名进行查询,
如果输入住址,按住址进行查询,
如果两者都输入,两个条件都要成立。

【需求分析】

1、如果输入了用户名按照用户名进行查询,

SELECT * FROM  user WHERE user_name = '孙悟空';

2、如果输入住址,按住址进行查询,

SELECT * FROM  user WHERE address='花果山水帘洞';

3、如果两者都输入,两个条件都要成立。

SELECT * FROM  user WHERE user_name = '孙悟空' AND address='花果山水帘洞';
3.1、定义接口方法

在UserMapper接口中定义如下方法:

List<User> queryByUserNameAndAge(@Param("userName") String userName, @Param("address") String address);
3.2、编写SQL

在UserMapper.xml中编写SQL

 <!--
        如果输入了用户名按照用户名进行查询,
        如果输入住址,按住址进行查询,
        如果两者都输入,两个条件都要成立。

        说明:如果按照如下写sql语句会有问题,假设用户名username是空,那么用户名的sql语句不参与条件,此时
        sql语句就会变为:SELECT * FROM  user where AND address = #{address}
        where后面直接书写了and显然不满足sql语句语法,这里会报错
        我们可以使用where标签解决上述问题:
             where标签:拼接多条件查询时 1、能够添加where关键字; 2、能够去除多余的and或者or关键字
    -->
   <!-- <select id="queryByUserNameAndAge" resultType="user">
        SELECT * FROM  user where
            <if test="userName != null and userName.trim()!=''">
                username = #{userName}
            </if>
            <if test="address!=null and address.trim()!=''">
                AND address = #{address}
            </if>
    </select>-->
    <!-- SELECT * FROM user WHERE address = ?
        where子标签将and去掉了
    -->
    <select id="queryByUserNameAndAge" resultType="user">
        SELECT * FROM  user
        <where>
            <if test="userName != null and userName.trim()!=''">
                username = #{userName}
            </if>
            <if test="address!=null and address.trim()!=''">
                AND address = #{address}
            </if>
        </where>
    </select>

说明:

1.说明:如果按照如下写sql语句会有问题,假设用户名username是空,那么用户名的sql语句不参与条件,此时
sql语句就会变为:SELECT * FROM user where AND address = #{address}
where后面直接书写了and显然不满足sql语句语法,这里会报错
我们可以使用where标签解决上述问题:
where标签:拼接多条件查询时 1、能够添加where关键字; 2、能够去除多余的and或者or关键字

2.SELECT * FROM user WHERE address = ?
where子标签将and去掉了

3.3、测试
@Test
    public void queryByUserNameAndAge() {
        List<User> userList = userMapper.queryByUserNameAndAge("", "花果山水帘洞");
        System.out.println("userList = " + userList);
    }

在这里插入图片描述

只传入住址,此时where子标签去掉了and.

【小结】

1、<where>标签作用:用于拼接多选一或者同时成立的SQL情况;
2、<where>还会根据情况,动态的去掉SQL语句中的AND或者or;

4、set

set标签:在update语句中,可以自动添加一个set关键字,并且会将动态sql最后多余的逗号去除。

案例:修改用户信息,如果参数user中的某个属性为null,则不修改。

如果在正常编写更新语句时,如下:

在这里插入图片描述

update user SET username = ?, birthday=?, sex=?, where id = ? 

那么一旦在传递的参数中没有address,此时生成的sql语句就会因为多了一个逗号而报错。

4.1、定义接口方法

在UserMapper接口中定义如下方法:

void updateSelectiveUser(User user);
4.2、编写SQL

在UserMapper.xml文件中编写如下SQL:

    <!--选择性地对user数据进行修改-->
   <update id="updateSelectiveUser">
        update user
        <set>
            <if test="username != null and username.trim()!=''">
                username = #{username},
            </if>
            <if test="birthday != null">
                birthday=#{birthday},
            </if>
            <if test="sex != null and sex.trim()!=''">
                sex=#{sex},
            </if>
            <if test="address != null and address.trim()!=''">
                address=#{address}
            </if>
        </set>
        where id = #{id}
    </update>
4.3、测试
 @Test
    public void updateSelectiveUser() {
        User user = new User();
        user.setUsername("锁哥1");
        user.setBirthday(new Date());
        user.setSex("男");
        user.setAddress("");

        user.setId(7);
        userMapper.updateSelectiveUser(user);
    }

【结果】

 update user SET username = ?, birthday=?, sex=? where id = ? 

【小结】

1、<set>标签替代了sql语句中的set关键字;
2、<set>标签还能把sql中多余的,去掉;

5、foreach

foreach标签:遍历集合或者数组
<foreach collection="集合名或者数组名" item="元素" separator="标签分隔符" open="以什么开始" close="以什么结束">
   #{元素}
</foreach>
	collection属性:接收的集合或者数组,集合名或者数组名
	item属性:集合或者数组参数中的每一个元素 
	separator属性:标签分隔符 
	open属性:以什么开始 
	close属性:以什么结束

需求:按照id值是1,2,3来查询用户数据;

5.1、定义接口方法

在UserMapper接口中定义如下方法:

List<User> queryByIds(@Param("arrIds") Integer[] arrIds);

这里一定加@Param(“arrIds”),否则报错

5.2、编写SQL
	<!--根据多个id值查询-->
    <select id="queryByIds" resultType="user">
        SELECT * FROM  user WHERE id IN
        <foreach collection="arrIds" item="ID" separator="," open="(" close=")">
            #{ID}
        </foreach>
    </select>
5.3、测试
    @Test
    public void queryByIds() {
        Integer[] arrIds = {1,2,3};
        List<User> userList = userMapper.queryByIds(arrIds);
        System.out.println("userList = " + userList);
    }

在这里插入图片描述

【小结】

<foreach>标签的作用:用于对查询参数进行遍历取值;

6、小结

If标签:条件判断
	test属性:编写ognl表达式

where标签:用于sql动态条件拼接,添加where关键字,可以将动态sql多余的第一个and或者or去除。

set标签: 用于更新语句的拼接,添加set关键字,并可以将动态sql中多余的逗号去除

foreach标签:用于遍历参数中的数组或者集合
	collection属性:参数中的数组或者集合
	item属性:表示数组或者集合中的某个元素,取出数据使用#{item的属性值}
	separator属性:分隔符
	open:以什么开始
	close:以什么结束

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

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

相关文章

网安小贴士(2)OSI七层模型

一、前言 OSI七层模型是一种网络协议参考模型&#xff0c;用于描述计算机网络体系结构中的不同层次和功能。它由国际标准化组织 (ISO) 在1984年开发并发布。 二、定义 OSI七层模型&#xff0c;全称为开放式系统互联通信参考模型&#xff08;Open Systems Interconnection Refe…

微型导轨:手术机器人的高精度“骨骼”

微型导轨精度高&#xff0c;摩擦系数小&#xff0c;自重轻&#xff0c;结构紧凑&#xff0c;被广泛应用在医疗器械中&#xff0c;尤其是在手术机器人中的应用&#xff0c;通过手术机器人&#xff0c;外科医生可以远离手术台操纵机器人进行手术。可以说&#xff0c;是当之无愧的…

6-linux操作文件与数据上传

目录 通配符学习 创建和上传下载文件 系统盘与数据盘 创建和查找文件夹 文件上传与移动 Windows上传文件到服务器方法1 Windows上传文件到服务器方法2&#xff1a;网盘等 删除文件 rm 复制文件cp 移动文件 常用的命令 cp:复制文件和目录。 mv:移动或重命名文件和目…

「漏洞复现」时空智友ERP系统updater.uploadStudioFile 任意文件上传漏洞

0x01 免责声明 请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;作者不为此承担任何责任。工具来自网络&#xff0c;安全性自测&#xff0c;如有侵权请联系删…

九浅一深Jemalloc5.3.0 -- ①浅*编译调试

目前市面上有不少分析Jemalloc老版本的博文&#xff0c;但5.3.0却少之又少。而且5.3.0的架构与之前的版本也有较大不同&#xff0c;本着“与时俱进”、“由浅入深”的宗旨&#xff0c;我将逐步分析Jemalloc5.3.0的实现。5.3.0的特性请见Releases jemalloc/jemalloc GitHub 另…

Chrome备份数据

Chrome备份数据 1、 导出谷歌浏览器里的历史记录 参考&#xff1a;https://blog.csdn.net/qq_32824605/article/details/127504219 在资源管理器中找到History文件&#xff0c;文件路径&#xff1a; C:\Users\你的电脑用户名\AppData\Local\Google\Chrome\User Data\Default …

2024年06月CCF-GESP编程能力等级认证Scratch图形化编程三级真题解析

本文收录于《Scratch等级认证CCF-GESP图形化真题解析》专栏,专栏总目录:点这里,订阅后可阅读专栏内所有文章。 一、单选题(共 15 题,每题 2 分,共 30 分) 第1题 小杨父母带他到某培训机构给他报名参加 CCF 组织的 GESP 认证考试的第 1 级,那他可以选择的认证语言有几…

前端工程化09-webpack静态的模块化打包工具(未完结)

9.1、开发模式的进化历史 webpacks是一个非常非常的强大的一个工具&#xff0c;相应的这个东西的学习也是有一定的难度的&#xff0c;里边的东西非常的多&#xff0c;里面涉及到的 概念的话也是非常非常的多的。 这个东西既然非常重要&#xff0c;那么在我们前端到底处于怎样…

如何在面试中找到最优秀的候选人:雇佣问题的随机化算法探索

目录 一、雇佣问题 二、雇佣问题的本质 三、引入随机化算法的思考过程 &#xff08;一&#xff09;随机排列 &#xff08;二&#xff09;预面试期 &#xff08;三&#xff09;正式雇佣期 四、概率分析 &#xff08;一&#xff09;预面试期的选择 &#xff08;二&#…

昇思25天学习打卡营第12天 | 基于MobileNetv2的垃圾分类函数式自动微分

基于MobileNetv2的垃圾分类 本文档主要介绍垃圾分类代码开发的方法。通过读取本地图像数据作为输入&#xff0c;对图像中的垃圾物体进行检测&#xff0c;并且将检测结果图片保存到文件中。 1、实验目的 了解熟悉垃圾分类应用代码的编写&#xff08;Python语言&#xff09;&a…

基于STM32的八位数码管显示和闹钟计时【Proteus仿真】

某鱼&#xff1a;两栖电子 一、系统功能 采用矩阵键盘&#xff0c;按下对应的数字再按下确认按键&#xff0c;数码管会显示自己输入的数字&#xff0c;如果按错可以使用删除按钮进行删除。点击计时按钮可以显示当前的时间。 二、使用器件 DS1302实时时钟芯片&#xff0c;8位数…

VUE3-Elementplus-form表单-笔记

1. 结构相关 el-row表示一行&#xff0c;一行分成24份 el-col表示列 (1) :span"12" 代表在一行中&#xff0c;占12份 (50%) (2) :span"6" 表示在一行中&#xff0c;占6份 (25%) (3) :offset"3" 代表在一行中&#xff0c;左侧margin份数 el…

实验5 图像分割

1. 实验目的 ①掌握图像分割的含义与目的&#xff1b; ②掌握迭代法、最大类间方差法、直方图法等阈值分割方法&#xff1b; ③掌握霍夫变换、区域生长法、区域分裂与合并法的原理&#xff0c;并能编程实现。 2. 实验内容 ①调用Matlab / PythonOpenCV中的相关函数&#xff…

【数据库】PostgreSQL数据库设计说明书(编制参考)

数据库设计说明书要点应包含&#xff1a;项目概述、数据库选型、逻辑设计、物理设计、数据安全与性能。简述项目需求与背景&#xff0c;选择适当的数据库系统&#xff0c;明确数据表结构、关系及索引设计&#xff0c;描述存储过程、触发器等逻辑组件。同时&#xff0c;强调数据…

使用 fvm 管理 Flutter 版本

文章目录 Github官网fvm 安装Mac/Linux 环境Windows 环境 fvm 环境变量fvm 基本命令 Github https://github.com/leoafarias/fvmhttps://github.com/flutter/flutter 官网 https://fvm.app/ fvm 安装 Mac/Linux 环境 Install.sh curl -fsSL https://fvm.app/install.sh …

探索ChatGPT是如何改变癌症护理

了解生成式人工智能&#xff08;尤其是 ChatGPT&#xff09;如何通过高级数据集成和个性化患者管理来增强诊断和治疗&#xff0c;从而改变癌症治疗。了解 Color Health 的创新副驾驶模型及其对早期检测和患者结果的影响。 近年来&#xff0c;人工智能与医疗保健的融合为癌症治疗…

Springboot ResourceLoader获取指定package目录下所有的类(get class in jar on Linux)

get class in jar on Linux Springboot ResourceLoader获取指定package目录下所有的类 PathMatchingResourcePatternResolver resolver new PathMatchingResourcePatternResolver();String pattern ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX ClassUtils.convertClas…

远程过程调用PRC

简介 远程过程调用&#xff08;Remote Procedure Call, RPC)&#xff0c;是一个计算机通信协议。该协议允许运行于一台计算机的程序调用另一个地址空间的子程序&#xff0c;且不需要考虑交互作用的细节。 RPC是一种服务器&#xff0c;客户端模式&#xff0c;是一个通过发送请…

[2024-6-30]如何获取OpenAI API Key/OpenAI密钥

一、前言 由于官网页面更新&#xff0c;获取路径与之前有所不同。 二、获取路径 1.点击Products&#xff0c;再点击API login 2.点击API 3. 如果需要登录&#xff0c;则登录 4.点击API keys&#xff0c;再点击Create new secret key

基于机器学习的制冷系统过充电和欠充电故障诊断(采用红外热图像数据,MATLAB)

到目前为止&#xff0c;制冷系统故障诊断方法已经产生很多种&#xff0c;概括起来主要有三大类&#xff1a;基于分析的方法&#xff0c;基于知识的方法和基于数据驱动的方法。基于分析的方法主要获得制冷系统的数学模型&#xff0c;通过残差来检测和诊断故障。如果存在残差且很…