别再手动拼接 SQL 了,MyBatis 动态 SQL 写法应有尽有,建议收藏!

一、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 的功能。

二、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标记的功能

①、用 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>

最后说一句(求关注!别白嫖!)

如果这篇文章对您有所帮助,或者有所启发的话,求一键三连:点赞、转发、在看。

关注公众号:woniuxgg,在公众号中回复:笔记  就可以获得蜗牛为你精心准备的java实战语雀笔记,回复面试、开发手册、有超赞的粉丝福利!

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

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

相关文章

[SaaS] 淘宝设AI

“淘宝设计AI” 让国际大牌造世界双11超级品牌 超级发布https://mp.weixin.qq.com/s/xFVDARQHxlweKAYG91DtYw下面是一个完整的品牌营销海报设计流程&#xff0c;AIGC起到了巨大作用&#xff0c;但是仍然很难去一步解决这个问题&#xff0c;还是逐步修改的一个过程。 Midjouner…

分布式与集群,二者区别是什么?

&#x1f413;分布式 分布式系统是由多个独立的计算机节点组成的系统&#xff0c;这些节点通过网络协作完成任务。每个节点都有自己的独立计算能力和存储能力&#xff0c;可以独立运行。分布式系统的目标是提高系统的可靠性、可扩展性和性能。 分布式服务包含的技术和理论 负…

LabVIEW多表位数字温湿度计图像识别系统

LabVIEW多表位数字温湿度计图像识别系统 解决数字温湿度计校准过程中存在的大量需求和长时间校准问题&#xff0c;通过LabVIEW开发平台设计了一套适用于20多个表位的数字温度计图像识别系统。该系统能够通过图像采集、提取和处理&#xff0c;进行字符训练&#xff0c;从而实现…

胸闷气短、失眠焦虑、植物神经紊乱治疗!

植物神经紊乱是一种内脏功能失调的综合征&#xff0c;是由于社压会力、工作压力、生活压力等等因素而导致的一种神经类疾病。长期患有这个疾病会给患者的生活、工作以及学习带来很严重的影响和危害。 有很多患有植物神经紊乱的患者&#xff0c;各种各样的症状的患者被所轻或重的…

中小企业的智能化,不能再拖了!

在当今时代&#xff0c;新质生产力已然成为了国内最热门的话题。它代表着先进生产力的涌现和发展&#xff0c;正逐渐成为推动国家经济社会持续发展的核心力量。今年的两会更是将“新质生产力”写入政府工作报告&#xff0c;并将其列为2024年政府工作十大任务之首&#xff0c;足…

【JS】parseInt与Math.floor的区别

获取两数区间随机整数的函数如下 function getRandom(min,max){return Math.floor(Math.random() * (max - min) min) }这个函数中&#xff0c;只可以使用Math.random&#xff0c;parseInt会出问题&#xff0c;二者虽然都是取整&#xff0c;但又有一些区别。 parseInt是「向…

力扣大厂热门面试算法题 30-32

30. 串联所有单词的子串&#xff0c;31. 下一个排列 &#xff0c;32. 最长有效括号&#xff0c;每题做详细思路梳理&#xff0c;配套Python&Java双语代码&#xff0c; 2024.03.15 可通过leetcode所有测试用例。 目录 30. 串联所有单词的子串 解题思路 完整代码 Java …

Sora学习手册

一&#xff0c;基本介绍 在2024年2月16日&#xff0c;Open AI宣布推出全新的生成式人工智能模型"Sora"。据了解,通过文 本指令&#xff0c;Sora 可以直接输出长达60秒的视频&#xff0c;并且包含高度细致的背景、复杂的多角度镜头,以 及富有情感的多个角色。 这意味…

【Java】String字符串及常用API

目录 一、字符串 1、 字符串是常量&#xff0c;不可改变 2、创建字符串的方式&#xff1a; 3、StringBuilder和StringBuffer 二、String字符串常用方法 1、以指定字符串开头或结尾startsWith、endWith 2、字符串截取 substring(beginIndex,endIndex)/substring(beginInd…

算法笔记 连载中。。。

HashMap&#xff08;会根据key值自动排序&#xff09; HashMap<String, Integer> hash new HashMap<>() hash.put(15,18) hash.getOrDefault(ts, -1) //如果ts(key)存在&#xff0c;返回对应的value 否则返回-1 hashMap1.get(words1[i])1会报错&#xff0c;因…

AcWing 848. 有向图的拓扑序列

#include<iostream> #include<cmath> #include<queue> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; const int N1e510; int n,m,a,b; int e[N],ne[N],h[N],idx; int d[N],top[N],cnt1;//top是拓扑排序…

Linux学习笔记:什么是文件描述符

什么是文件描述符 C语言的文件接口文件的系统调用什么是文件描述符,文件描述符为什么是int类型?为什么新打开的文件的文件描述符不是从0开始? 文件描述符 fd (file descriptor) C语言的文件接口 当时学习C语言的时候,学习了文件接口 具体可以查看之前的文章: 链接:C语言的文…

flask库

文章目录 flask库1. 基本使用2. 路由路径和路由参数3. 请求跳转和请求参数4. 模板渲染1. 模板变量2. 过滤器3. 测试器 5. 钩子函数与响应对象 flask库 flask是python编写的轻量级框架&#xff0c;提供Werkzeug&#xff08;WSGI工具集&#xff09;和jinjia2&#xff08;渲染模板…

【基于PSINS】误差计算函数

输入真值 (参考值)、对比量、待比较值,输出误差的最大值、平均值、标准差的函数 程序源码 function [err] = EV_error_output(out_flag,avp_flag,avp,varargin) % draw_flag:以字符串的形式输入绘图的数据,eg:["EKF","UKF"] % avp:基准 % avp_:…

【PyTorch】基础学习:在Pycharm等IDE中打印或查看Pytorch版本信息

【PyTorch】基础学习&#xff1a;在Pycharm等IDE中打印或查看Pytorch版本信息 &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程&#x1…

机器硬件命令

一、查看机器核数 有以下几种方法 1、lscpu命令 lscpu命令可以显示关于CPU的信息&#xff0c;包括核数、线程数等。在终端中输入以下命令即可查看CPU核数&#xff1a;该命令会输出CPU每个物理插槽的核数。 lscpu | grep "Core(s) per socket" | awk {print $NF} …

PHPadmin写shell的方法

一、常规导入 shell 的操作创建数据表导出 shell CREATE TABLE mysql.shadow9 (content TEXT NOT NULL ); INSERT INTO mysql.shadow9 (content ) VALUES (‘<?php eval($_POST[pass]);?>’); SELECT content FROM shadow9 INTO OUTFILE ‘C:\\phpStudy\\WWW\\90sec.…

C++中实现String类

String类实现 概述示例开发环境代码运行结果 注意 概述 本文主要记录自己实现一个String类中的部分功能。 示例 开发环境 Windows下Visual Studio 2019。 代码 MyString.h #pragma once #include <iostream>class MyString{ public:MyString();MyString(char *p);…

github登录时解决2FA问题

使用Edge浏览器下载插件 https://microsoftedge.microsoft.com/addons/detail/authenticator-2fa-client/ocglkepbibnalbgmbachknglpdipeoio 下载后弹框会显示是否添加&#xff0c;添加。如下&#xff1a; Chrome下 https://chrome.google.com/webstore/detail/authenticator…

数据结构维度的索引及其应用场景

B树索引 B树索引是MySQL中广泛采用的数据结构&#xff0c;它将所有实际数据存储在叶子节点上&#xff0c;形成一个有序链表结构。B树索引的查询复杂度为O(logn)&#xff0c;非常适合执行范围查询操作&#xff0c;因其索引结构能高效地对区间内的数据进行遍历。 B树索引特点&a…