MyBatis - 动态 SQL

news/2024/11/22 20:36:58/

文章目录

    • 1.if
    • 2.choose
    • 3.where
    • 4.set
    • 5.foreach
    • 6.基于注解编写

动态 SQL 是 MyBatis 提供的一个非常强大的功能,它可以让我们在运行时构建 SQL 语句。这意味着我们可以根据应用程序的需求来构建符合要求的 SQL。通常情况下,这是非常有用的,因为有时我们不知道要查询哪些表,或者要查询哪些列。此外,动态 SQL 还可以用来构建动态修改或删除语句。

1.if

if 标签可以实现判断逻辑,该标签有一个 test 属性定义成立条件。如果条件成立,那么包含在标签中的 SQL 语句将会被执行,否则这些语句将会被忽略。

下面是一个示例:

<select id="getUser" resultType="User">SELECT * FROM users WHERE 1=1<if test="username != null">AND username = #{username}</if><if test="email != null">AND email = #{email}</if>
</select>

我们定义了一个 getUser 的 SQL 查询,并在查询中使用了 IF 条件语句。这个查询将会根据传入的参数选择是否加入用户名和电子邮件地址条件,从而查询符合条件的用户记录。

注意:为了是我们的 SQL 拼接不出错,我们添加了 WHERE 1=1 这样的语句。

2.choose

如果我们需要在两个或更多条件之间进行选择,我们可以使用 choose 标签。

它的语法如下:

<select id="getUser" resultType="User">SELECT * FROM users<choose><when test='condition1'>WHERE column_name = #{column_name1}</when><when test='condition2'>WHERE column_name = #{column_name2}</when><otherwise>WHERE column_name = #{column_name3}</otherwise></choose>
</select>

我们定义了一个 getUser 的 SQL 查询,并在查询中使用 choose 标签。这个查询首先会根据 condition1 的值是否成立进行判断。如果成立,那么查询结果只会包括 column_name1 的内容。否则,它会继续检查 condition2 是否成立。如果成立,那么查询结果只会包括 column_name2 的内容。否则,查询结果将会包括 column_name3 的内容。

TIP:可以简单类比为 Java 中的 Switch 语句。

3.where

上面的例子中我们为了 SQL 拼接不出错,添加了 where 1=1 这样的语句,其实可以使用 where 标签来实现查询条件,当标签内没有内容时会自动去除 where 关键字,同时还会去除开头多余的 and 关键字,帮助我们在 SQL 查询中简化条件逻辑。

它的语法如下:

SELECT * FROM table_name
<where><if test="column_name1 != null">AND column_name1 = #{column_name1}</if><if test="column_name2 != null">AND column_name2 = #{column_name2}</if><if test="column_name1 != null">AND column_name3 = #{column_name3}</if>
</where>

4.set

当我们拼接更新字段的语句时,也会面临同样的问题,此时可以使用 set 标签来解决。

它的语法如下:

UPDATE table_name
<set>column_name1 = #{column_name1},column_name2 = #{column_name2},column_name3 = #{column_name3},<if test="column_name4 != null">column_name4 = #{column_name4},</if>
</set>
WHERE id = #{id}

5.foreach

通过 foreach 我们可以实现一些循环拼接 SQL 的逻辑,它一般用于循环遍历一个集合,然后将集合中的元素插入到 SQL 语句中,从而生成多条 SQL 语句。

它的语法如下:

<foreach collection="list" item="item" index="index" separator=",">#{item}
</foreach>

下面是 foreach 标签常用属性:

  • list:表示要遍历的集合元素;

  • item:表示集合中的元素变量,即每次循环时,将集合中的某个元素赋值给该变量;

  • index:表示集合中元素的索引值,从0开始计数;

  • separator:表示单个元素之间的分隔符。

  • open:用于指定循环的开始语句字符;

  • close:用于指定循环的结束语句字符;

假设有一个列表,其中包含多个用户的 ID,我们想通过这个列表查询他们的姓名。使用 foreach,我们可以轻松地将这些用户 ID 插入到 SQL 语句中:

<select id="getUserListByIds" resultType="User">select * from user where id in<foreach collection="ids" item="item" index="index" open="(" separator="," close=")">#{item}</foreach>
</select>

其中 ids 是用户 ID 列表,在 foreach 语句中将其遍历并插入到 SQL 语句中。这将生成类似于以下的 SQL 语句:

select * from user where id in (1, 2, 3, 4)

6.基于注解编写

上面我们都是默认使用 MyBatis XML 映射的方式进行动态 SQL 的讲解,其实动态 SQL 也支持注解的方式。

从最简单的查询开始,假设我们有一个名为 StudentMapper 的接口,并且我们希望根据不同的条件来查询用户列表。

@Select("select * from student where id = #{id}")
Student selectById(Long id);@Select("select * from student where name = #{name}")
Student selectByName(String name);

针对这种情况,我们就可以使用动态 SQL 来进行优化了。接下来,我们将扩展查询功能,以便能够根据不同的条件进行动态查询。在这种情况下,我们可以使用 @SelectProvider 注解来指定一个动态 SQL 提供者类。

@SelectProvider(type = StudentSqlProvider.class, method = "selectById")
Student selectById(Long id);@SelectProvider(type = StudentSqlProvider.class, method = "selectByName")
Student selectByName(String name);

上面我们通过 @SelectProvider 注解的 type 属性指定了动态 SQL 提供者类为 StudentSqlProvider,并通过 method 属性指定了其中处理对应情况的方法名。

对此我们便可以提供一个内部类 StudentSqlProvider 来进行具体实现了:

class StudentSqlProvider {public String selectById(Long id) {return "select * from student where id = " + id;}public String selectByName(String name) {return "select * from student where name = '" + name + "'";}
}

接下来我们加入动态 SQL,再来进行进一步的优化:

class StudentSqlProvider {public String selectById(Long id) {return new SQL() {{SELECT("*");FROM("student");WHERE("id = #{id}");}}.toString();}public String selectByName(String name) {return new SQL() {{SELECT("*");FROM("student");WHERE("name = #{name}");}}.toString();}
}

在上面的代码中,我们定义了一个名为 UserSqlProvider 的类,其中包含了动态 SQL 查询的实现。这些方法返回一个动态生成的 SQL 语句,MyBatis 将在运行时执行该语句。

除了简单的查询条件外,有时我们需要使用条件判断和循环来构建更复杂的查询语句。在 MyBatis 注解中,我们可以使用 OGNL 表达式来实现这些逻辑。

OGNL(Object-Graph Navigation Language)是一种强大的表达式语言,用于在对象图中导航和操作对象的属性和方法。在 MyBatis 中,OGNL 表达式用于在注解中编写动态 SQL 查询的条件判断和循环逻辑。OGNL 表达式使用点号 . 来访问对象的属性和方法。例如,user.name 表示访问 user 对象的 name 属性,user.getName() 表示调用 user 对象的 getName() 方法。

例如,我们现在将上述两个方法再进一步优化,合并为一个方法:

@SelectProvider(type = StudentSqlProvider.class, method = "getStudentByCondition")
Student selectByCondition(Student student);

然后再次修改对应的动态 SQL 提供者类:

class StudentSqlProvider {public String getStudentByCondition(Student student) {SQL sql = new SQL().SELECT("*").FROM("student");if (student.getId() != null) {sql.WHERE("id = #{id}");}if (student.getName() != null) {sql.WHERE("name = #{name}");}return sql.toString();}
}

在上述代码中,我们将根据不同的条件动态构建 SQL 查询语句,从而实现动态 SQL 的效果。

对于动态 SQL 的注解,一共提供有如下 4 个:

注解名说明
@SelectProvider用于指定一个动态 SQL 提供者类,该类负责根据方法参数生成动态 SQL 语句。
@InsertProvider用于指定一个动态 SQL 提供者类,该类负责根据方法参数生成动态插入语句。
@UpdateProvider用于指定一个动态 SQL 提供者类,该类负责根据方法参数生成动态更新语句。
@DeleteProvider用于指定一个动态 SQL 提供者类,该类负责根据方法参数生成动态删除语句。

使用方式都是大同小异的,根据实际情况进行选择即可。


http://www.ppmy.cn/news/148625.html

相关文章

Android 12系统源码_窗口管理(四)RootWindowContainer简介

前言 在Android 12中,RootWindowContainer是一个重要的类,它是WindowManagerService的主要组成部分之一,用于管理所有应用程序的窗口。它表示整个屏幕上的最顶层的容器,包括状态栏、导航栏和所有应用的窗口。 一、RootWindowContainer的创建 1、RootWindowContainer是在…

tcpdump 抓包工具详细图文教程(上)

目录 一、tcpdump 抓包工具的基本介绍和学习基础 1.1 常用的抓包工具 1.2 tcpdump 抓包工具介绍 二、tcpdump 抓包工具使用环境和初体验 2.1 编译安装 tcpdump 2.2 抓包 三、讲解 TCP 协议报文报头 四、tcpdump 抓包工具常规过滤规则 4.1 tcpdump 的 host 和 net 过…

MVCC 实现原理

&#x1f49f;这里是CS大白话专场&#xff0c;让枯燥的学习变得有趣&#xff01; &#x1f49f;没有对象不要怕&#xff0c;我们new一个出来&#xff0c;每天对ta说不尽情话&#xff01; &#x1f49f;好记性不如烂键盘&#xff0c;自己总结不如收藏别人&#xff01; &#x1f…

佳能EF镜头控制器

机器视觉应用相机通常选择SLR镜头&#xff0c;牺牲了控制控制功能&#xff0c;所以不能用于远程控制。使用LC-2镜头控制系统搭配佳能(Canon)EF镜头可以配合机器视觉相机使用从而实现远程控制。 EF/EFS 镜头控制单元(LC-2) 适用于大部分佳能(Canon) EF和腾龙(Tamron) EF镜头 精…

什么镜头最适合拍风景_要拍风景和人像,分别买什么镜头比较好?

展开全部 没有固定的用法。 但是人像基本用特写的手法&#xff0c;那么中长焦镜头是e5a48de588b63231313335323631343130323136353331333365643632最好的选择&#xff0c;大光圈容易带来虚化的效果&#xff0c;更能突显人物&#xff0c;所以在摄影镜头中85mm和135mm两个经典定焦…

佳能7款PL卡口电影镜头发布在即

本文来自新摄影 在四月份NAB展会之前&#xff0c;佳能将发布7款PL卡口电影镜头。与此前的EF卡口电影镜头相比&#xff0c;这几款PL卡口镜头的光学设计略有不同&#xff0c;且拍摄出来的画面更加柔和、拥有更低的对比度。据了解&#xff0c;目前佳能只有6款CN-E电影变焦镜头镜头…

数码相机名词解释-变焦镜头 物距 枕形失真 视角 透视 微距摄影 焦距系数

转自&#xff1a;http://hi.baidu.com/hejundream/item/b95747fd985cc20fd89e7223 数码相机名词解释-变焦镜头 物距 枕形失真 视角 透视 微距摄影 焦距系数 照片四周发虚&#xff08;Vignetting&#xff09; 变焦镜头&#xff08;尤其是低端的变焦镜头&#xff09;&#x…

镜头选型——景深计算

正在上传…重新上传取消 1 概述 先看两个例子&#xff0c;拍摄花、昆虫等照片时&#xff0c;背景拍的比较模糊&#xff0c;突出被拍物。但当拍摄纪念照、风景等照片时&#xff0c;却会把背景拍摄得和被拍对象一样清晰。这两者就是不同景深。前者为浅景深&#xff0c;拍摄聚焦到…