MyBatis动态SQL、模糊查询与结果映射

news2024/12/28 15:51:56

目录

前言

一、MyBatis动态SQL

1.动态SQL是什么

2.动态SQL的作用

3.常用动态SQL元素

1. where + if 元素

2. set + if 元素

3. choose + when + otherwise 元素

4. 自定义 trim 元素

 <1>. 自定义 trim 元素改写上面的 where + if 语句

<2>. 自定义 trim 元素改写上面的 set + if 语句

5. foreach 元素

6.SQL片段重用

二、模糊查询的三种SQL方式、#和$的区别

三种模糊查询的方法是:

1.使用#{字段名}

2.使用${字段名}

3.使用concat{'%',#{字段名},'%'}

#与$的区别 

1.$ 符号(sql拼接符号) 

2. # 符号(占位符) 

四、MyBatis结果映射

映射场景

resultType进行结果映射

resultMap进行结果映射

总结


前言

在我们编写的sql语句的内容并不是固定的,会通过一些条件判断拼接成最终符合要求的sql语句。

本篇所讲的动态SQL,是mybatis通过标签元素的形式, 如if, choose, when, otherwise, trim, where, set, foreach等标签完成对sql的拼接功能,使用起来也非常灵活方便,大大提高了开发人员的工作效率!

一、MyBatis动态SQL

1.动态SQL是什么

动态SQL是一种根据不同条件动态生成SQL语句的技术。在MyBatis中,我们可以使用动态SQL来根据不同的查询条件生成不同的SQL语句,从而实现更灵活的查询。

2.动态SQL的作用

1. 条件查询:通过动态SQL,我们可以根据用户输入的条件动态生成查询语句,从而实现灵活的条件查询。例如,根据用户选择的不同筛选条件,我们可以动态地拼接SQL语句,实现根据不同条件查询不同的结果。

2. 动态排序:有时候我们需要根据用户的选择对查询结果进行排序。通过动态SQL,我们可以根据用户选择的排序字段和排序方式动态生成排序语句,从而实现按照不同的规则对查询结果进行排序。

3. 动态更新:有时候我们需要根据不同的条件更新数据库中的数据。通过动态SQL,我们可以根据不同的条件动态生成更新语句,从而实现根据不同的条件更新不同的数据。

4. 动态插入:有时候我们需要根据不同的条件插入数据到数据库中。通过动态SQL,我们可以根据不同的条件动态生成插入语句,从而实现根据不同的条件插入不同的数据。

3.常用动态SQL元素

下面我们将以用户表为例举例说明:

1. where + if 元素

先来个简单的需求,根据 username 和 sex 来查询user用户,首先看下普通的sql:

<select id="selectUserByNameAndSex" resultType="com.ctb.model.User" 
                        parameterType="com.kzy.entity.User">
    select * from user where username=#{username} and sex=#{sex}
</select>

这种方式如果其中一个参数为空,可能就会导致最终查询不到数据。

我们现在想实现如果username为空,将只根据sex来查询;如果sex为空,我们将只根据username来查询。那么可以使用 where + if 标签进行判断,sql如下:

<select id="selectUserByNameOrSex" resultType="com.ctb.model.User" 
                        parameterType="com.ctb.model.User">
    select * from user 
    <where>
        <if test="username != null">
           username=#{username}
        </if>
        <if test="sex != null">
           and sex=#{sex}
        </if>
    </where>
</select>

 if 元素:即根据条件判断是否显示其里面的内容。                                                                  where 元素:自行判断若下面的子元素有内容,则此处会添加一个'where',如果下面的子元素无内容,即条件判断都为空,则此处不添加'where'。此外,如果where标签内容以'and' 或 'or'开头的话,会将and/or自动剔除(否则 'where and/or' 连在一起会报语法错误)。

2. set + if 元素

不仅查询操作可能会用到动态sql,有时一些更新操作也会需要根据前端传来的参数进行判断,拼接符合条件的sql语句,如下:

<update id="updateUserById" parameterType="com.ctb.model.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>
     where id=#{id}
</update>

若第一个条件 username 为空,那么 sql 语句为:update user u set u.sex=? where id=?

若第一个条件不为空,那么 sql 语句为:update user u set u.username = ? ,u.sex = ? where id=?

多个条件以此类推,最后一个if标签里的内容结尾不用加逗号,是为了防止出现 '... , where ...' 语法错误。

3. choose + when + otherwise 元素

有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。

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

业务还是查询user,三个条件分别为 id,username,sex,但是策略变为只选择一个作为查询条件:传入 “id” ,对应的sql语句就是 select * from user where  id=?; 

传入 “username” ,对应的sql语句就是 select * from user where  username=?;

如果前两者都没有传入,那么默认选择<otherwise>标签里的内容,对应的查询语句为 select * from user where sex=?;

4. 自定义 trim 元素

如果 where 或者 set 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 或 set 的功能,非常实用!

 <1>. 自定义 trim 元素改写上面的 where + if 语句
<select id="selectUserByNameOrSex" resultType="com.ctb.model.User" parameterType="com.ctb.model.User">
    select * from user
    <!-- <where>
            <if test="username != null">
               username=#{username}
            </if>
            <if test="sex != null">
               and sex=#{sex}
            </if>
        </where>  -->
    <!-- 改写后的效果 -->
    <trim prefix="where" prefixOverrides="and | or">
        <if test="username != null">
            username=#{username}
        </if>
        <if test="sex != null">
            and sex=#{sex}
        </if>
    </trim>
</select>

prefix:插入 prefix 属性中指定的内容,即前缀。

prefixoverride:前缀覆盖,去掉第一个and 或者or,即 prefixoverride 属性中的内容,此处为了防止拼接sql时出现" where and "这种情况。

<2>. 自定义 trim 元素改写上面的 set + if 语句
<update id="updateUserById" parameterType="com.ctb.model.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>

suffixoverride:后缀覆盖,去掉最后一个逗号,即 suffixoverride 属性中的内容,此处为了防止拼接sql时出现尾部多个逗号这种情况。

5. foreach 元素

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

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

例如:现在我们有个简单的sql语句:select * from user where id in (1,2,3);

现在我们来对它进行改写 :

<select id="selectUserByListId" parameterType="java.util.List" resultType="com.ctb.model.User">
    select * from user
    where id in
        <!--
            collection:指定输入对象中的集合属性,可以是array数组,也可是list集合
            item:每次遍历生成的对象
            open:开始遍历时的拼接字符串
            close:结束时拼接的字符串
            separator:遍历对象之间需要拼接的字符串
            select * from user where id in (1,2,3)
          -->
        <foreach collection="list" item="id" open="(" close=") " separator=",">
            #{id}
        </foreach>
</select>

foreach 元素内各个属性对应的含义:                                                                                 

collection:指定输入对象中的集合属性,可以是array数组,也可是list集合
item:每次遍历生成的对象
open:开始遍历时的拼接字符串
close:结束时拼接的字符串
separator:遍历对象之间需要拼接的字符串

6.SQL片段重用

该作用于当我们经常需要使用某表的某些字段时,我们可以它分装起来,便于直接引用。

<sql id="userColumns">
  id, name, sex,birthday
</sql>
 
<select id="selectUsers" resultMap="BaseResultMap">
  SELECT <include refid="userColumns" />
  FROM t_user
</select>
 
<select id="selectUsersWithPrice" resultMap="BaseResultMap">
  SELECT <include refid="userColumns" />, info
  FROM t_user
</select>

        在这个示例中,通过<sql>标签定义了一个名为bookColumns的SQL片段,包含了书籍表的列名。然后,在不同的查询语句中通过<include>标签引用了该SQL片段,实现了列名的重用。

二、模糊查询的三种SQL方式、#和$的区别

三种模糊查询的方法是:

1.使用#{字段名}

<select id="like1" resultType="com.ctb.model.Book" parameterType="java.lang.String" >
    select
    <include refid="Base_Column_List" />
    from t_mvc_book
    where bname like #{bname}
  </select>

测试结果

2.使用${字段名}

<select id="like2" resultType="com.ctb.model.Book" parameterType="java.lang.String" >
    select
    <include refid="Base_Column_List" />
    from t_mvc_book
    where bname like ${bname}
  </select>

测试结果:  

3.使用concat{'%',#{字段名},'%'}

<select id="like3" resultType="com.ctb.model.Book" parameterType="java.lang.String" >
  select
  <include refid="Base_Column_List" />
  from t_mvc_book
  where bname like concat('%',#{bname},'%')
</select>

测试结果: 

#与$的区别 

1.$ 符号(sql拼接符号) 

  • $符号占位符是简单的字符串替换,不进行预编译和参数类型处理,也不会进行转义。
  • $符号占位符直接将参数的值替换到SQL语句中,可以用于动态拼接SQL语句的部分内容。
  • $符号占位符存在SQL注入的风险,因为参数值直接替换到SQL语句中,可能导致恶意注入攻击。
  • 没有 '引号'

2. # 符号(占位符) 

  • #符号占位符是预编译的占位符,会对参数进行类型处理和安全处理。
  • #符号占位符将参数值作为预编译参数传递给数据库,可以防止SQL注入攻击。
  • #符号占位符可以用于动态生成SQL语句的条件部分,例如WHERE子句、ORDER BY子句等。
  • 有引号

注:

1) mybatis中使用OGNL表达式传递参数
2) 优先使用#{...}
3) ${...}方式存在SQL注入风险 

#{...}更加安全可靠,适用于大多数情况下。而${...}则更加灵活,但需要注意潜在的安全风险。在使用${...}时,要确保参数值的来源可信,避免直接将用户输入的数据作为参数值传递进去。

四、MyBatis结果映射

Mybatis中结果集的处理分为两种:

resultMap:适合使用返回值是自定义实体类的情况

resultType:适合使用返回值的数据类型是非自定义的,即jdk的提供的类型

映射场景

①返回单表的对应的实体类,仅有一个查询结果,可以用resultType/resultMap。

②返回单表的对应的实体类,有多个查询结果,可以用resultType/resultMap。

③返回多表对应结果,仅有一个查询结果,通常用resultType也可以用resultMap。

④返回多表对应结果,有多个查询结果,通常用resultType也可以用resultMap。

⑤返回单个列段,仅有一个查询结果,就用resultType。

⑥返回单个列段,有多个查询结果,就用resultType。 

resultType进行结果映射

首先,我们需要定义一个User类,用于存储查询结果:

public class User {
    private int id;
    private String name;
    private int age;
    private String gender;
    private String email;
    // getter和setter方法省略
}

然后,在MyBatis的mapper文件中,我们可以使用resultType来映射查询结果到User对象上。具体配置如下:

<select id="getUserById" resultType="com.ctb.model.User">
  SELECT id, name, age, gender, email
  FROM user
  WHERE id = #{id}
</select>

在上面的配置中,我们使用了resultType属性来指定查询结果映射到的Java对象的全限定名。这样,当执行查询语句时,MyBatis会自动将查询结果映射到指定的Java对象上。

resultMap进行结果映射

首先,我们需要定义一个Order类,用于存储查询结果:

public class Order {
    private int id;
    private int userId;
    private int productId;
    private double price;
    private int quantity;
    // getter和setter方法省略
}

然后,在MyBatis的mapper文件中,我们可以使用resultMap来映射查询结果到Order对象上。具体配置如下:

<resultMap id="OrderResultMap" type="com.example.Order">
  <id property="id" column="id" />
  <result property="userId" column="user_id" />
  <result property="productId" column="product_id" />
  <result property="price" column="price" />
  <result property="quantity" column="quantity" />
</resultMap>
 
<select id="getOrderById" resultMap="OrderResultMap">
  SELECT id, user_id, product_id, price, quantity
  FROM order
  WHERE id = #{id}
</select>

在上面的配置中,我们定义了一个名为"OrderResultMap"的resultMap,它的type属性指定了要映射的Java对象的全限定名。接下来,我们为每个字段指定了对应的属性名和数据库表中的列名。最后,在查询语句中引用这个resultMap即可将查询结果映射到Order对象上。

需要注意的是,如果查询结果中的某个字段在Java对象中没有对应的属性,那么该字段将被映射为null。此外,如果查询结果中的某个字段在Java对象中有多个对应的属性,那么该字段的值将被映射为一个列表或数组。

总结

resultType用于指定查询结果的类型。它可以是Java的基本数据类型(如int、String等),也可以是自定义的Java对象。当查询结果只有一列时,可以使用resultType来指定该列的类型。例如,如果查询结果只有一个整数列,可以将resultType设置为int

resultMap用于定义复杂的查询结果映射关系。当查询结果包含多个列,并且需要将这些列映射到一个Java对象中时,可以使用resultMap来定义映射规则。resultMap可以指定每个列与Java对象的属性之间的映射关系,以及一些其他的映射规则,如类型转换、关联关系等。

resultType适用于简单的查询结果映射,而resultMap适用于复杂的查询结果映射。

MyBatis动态SQL、模糊查询与结果映射到这就结束了,

祝大家在编程之路越走越顺,越走越宽

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

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

相关文章

Go 语言的实战案例 SOCKS5 代理 | 青训营

Powered by:NEFU AB-IN 文章目录 Go 语言的实战案例 SOCKS5 代理 | 青训营 引入TCP echo serverauth 认证请求阶段relay阶段 Go 语言的实战案例 SOCKS5 代理 | 青训营 GO语言工程实践课后作业&#xff1a;实现思路、代码以及路径记录 引入 代理是指在计算机网络中&#xff…

硬件知识积累 LED的介绍与选型 (简单电路)

1. LED 的介绍 1.1 LED 是什么 LED :是一种能发光的半导体电子元件。发光二极管&#xff08;LED&#xff09;于20世纪60年代问世。在20世纪80年代之前&#xff0c;LED主要作为指示灯使用&#xff0c;从其光色来看&#xff0c;只有红光、橙光、黄光和绿光等几种。这一时期属于…

MyBatis动态语句且如何实现模糊查询及resultType与resultMap的区别---详细介绍

前言 前面我们学习了如何使用Mybatis实现简单的增删改查。今天我们来学习如何使用动态语句来根据不同的条件生成不同的SQL语句。这在实际开发中非常有用&#xff0c;因为通常查询条件是多样化的&#xff0c;需要根据实际情况来拼接SQL语句&#xff0c;那什么是MyBatis动态语句呢…

【Docker入门第一篇】

Docker简介 Docker 是一个开源的应用容器引擎&#xff0c;基于 Go 语言 并遵从 Apache2.0 协议开源。 Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中&#xff0c;然后发布到任何流行的 Linux 机器上&#xff0c;也可以实现虚拟化。 容器是完全使…

mysql数据备份批处理文件正式版已测试通过

这里写目录标题 1.数据库全表原始数据.ibd文件备份为.sql文件1.1理解date含义 2.备份原始表中部分表 --改进版2.1 backPartTable表内容2.2备份运行2.3实操代码 3.如何将备份的文件进行压缩处理&#xff1f;&#xff1f;执行压缩文件 1.数据库全表原始数据.ibd文件备份为.sql文件…

Android相机-HAL-Rockchip-hal3

引言&#xff1a; 对于Android相机的 HAL层而言对上实现一套Framework的API接口&#xff0c;对下通过V4L2框架实现与kernel的交互。不同的平台会有不同的实现方案。主要是对Android HAL3的接口的实现。看看rockchip是怎么支持hal3的&#xff1f; 代码目录&#xff1a; hardw…

浅析Linux追踪技术之kprobe:基于kprobes的Event Tracing

文章目录 概述内核选项配置ftrace配置接口kprobe事件配置 使用示例添加kprobes事件kprobes事件使能kprobes事件统计 参考链接 概述 常规的Event Tracing&#xff08;事件追踪&#xff09;是通过散落在Linux内核代码各处的Tracepoint来实现的&#xff0c;这些Tracepoint数量有限…

Docker部署MongoDB 5.0.5

1、查看目录 rootwielun:~# tree mongo mongo ├── conf │ └── mongod.conf ├── data ├── docker-compose.yml └── logrootwielun:~# cd mongo rootwielun:~/mongo# chmod 777 log2、配置docker-compose.yml rootwielun:~/mongo# cat docker-compose.yml ve…

RK3568 uart串口

一.简介 串口全称叫做串行接口&#xff0c;通常也叫做 COM 接口&#xff0c;串行接口指的是数据一个一个的顺序传 输&#xff0c;通信线路简单。使用两条线即可实现双向通信&#xff0c;一条用于发送&#xff0c;一条用于接收。串口通信 距离远&#xff0c;但是速度相对会低&a…

YOLOv5算法改进(3)— 添加CBAM注意力机制

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。注意力机制是近年来深度学习领域内的研究热点&#xff0c;可以帮助模型更好地关注重要的特征&#xff0c;从而提高模型的性能。CBAM&#xff08;Convolutional Block Attention Module&#xff09; 是一种用于前馈卷积神经…

Node基础--Node简介以及安装教程

1.Node简介 Node.js发布于2009年5月&#xff0c;由Ryan Dahl开发&#xff0c;是一个基于Chrome V8引擎的JavaScript运行环境&#xff0c;使用了一个事件驱动、非阻塞式I/O模型&#xff0c;让JavaScript 运行在服务端的开发平台&#xff0c;它让JavaScript成为与PHP、Python、Pe…

使用Maven父工程构建spring boot子工程

1.父工程删除src目录&#xff0c;pom文件配置parent为spring-boot-starter-parent 2.创建子工程&#xff0c;子工程引入一个springboot相关依赖 注意&#xff1a;子工程引入springboot相关依赖之后子工程才能被解析为springboot模块

Android SDK 上手指南||第五章 用户界面设计

第五章 用户界面设计 在本篇教程中我们将为应用程序项目添加布局方案&#xff0c;在这方面XML与Eclipse ADT接口将成为工作中的得力助手——不过在后面两节中还会用到一部分Java开发知识。XML与Java在Android平台的开发工作当中可谓无处不在&#xff0c;如果大家对二者还缺乏基…

Windows运行Spark所需的Hadoop安装

解压文件 复制bin目录 找到winutils-master文件hadoop对应的bin目录版本 全部复制替换掉hadoop的bin目录文件 复制hadoop.dll文件 将bin目录下的hadoop.dll文件复制到System32目录下 配置环境变量 修改hadoop-env.cmd配置文件 注意jdk装在非C盘则完全没问题&#xff0c;如果装在…

绕过__wakeup() 反序列化 合集

变量引用 这个其实不是语言特性漏洞&#xff0c;而是代码逻辑漏洞。只有在特定代码情况下才会产生 KaTeX parse error: Expected EOF, got & at position 3: x&̲a使两个变量同时指向同一个内存地址 利用&#xff1a; KaTeX parse error: Expected EOF, got & a…

ATF(TF-A)安全通告 TFV-2 (CVE-2017-7564)

安全之安全(security)博客目录导读 ATF(TF-A)安全通告汇总 目录 一、ATF(TF-A)安全通告 TFV-2 (CVE-2017-7564) 二、 CVE-2017-7564 一、ATF(TF-A)安全通告 TFV-2 (CVE-2017-7564) Title 启用安全自托管侵入式调试接口&#xff0c;可允许非安全世界引发安全世界panic CV…

路径总和 III-前缀和dfs

给定一个二叉树的根节点 root &#xff0c;和一个整数 targetSum &#xff0c;求该二叉树里节点值之和等于 targetSum 的 路径 的数目。 路径 不需要从根节点开始&#xff0c;也不需要在叶子节点结束&#xff0c;但是路径方向必须是向下的&#xff08;只能从父节点到子节点&…

汽车电子笔记之:AUTOSAR方法论及基础概念

目录 1、AUTOSAR方法论 2、AUTOSAR的BSW 2.1、MCAL 2.2、ECU抽象层 2.3、服务层 2.4、复杂驱动 3、AUTOSAR的RTE 4、AUTOSAR的应用层 4.1、SWC 4.2、AUTOSAR的通信 4.3、AUTOSAR软件接口 1、AUTOSAR方法论 AUTOSAR为汽车电子软件系统开发过程定义了一套通用的技术方法…

Cyanine3 NHS ester生物分子的标记与共价结合1032678-38-8

​欢迎来到星戈瑞荧光stargraydye&#xff01;小编带您盘点&#xff1a; Cyanine3 NHS ester是一种荧光染料&#xff0c;可用于将含有游离氨基&#xff08;-NH2&#xff09;的生物分子如蛋白质、抗体、肽段、核酸等进行标记和共价结合。这个过程通常称为NHS酯化反应&#xff0c…

归并排序之从微观看递归

前言 这次&#xff0c;并不是具体讨论归并排序算法&#xff0c;而是利用归并排序算法&#xff0c;探讨一下递归。归并排序的特点在于连续使用了两次递归调用&#xff0c;这次我们将从微观上观察递归全过程&#xff0c;从本质上理解递归&#xff0c;如果能看完&#xff0c;你一…