当前位置: 首页 > news >正文

再谈动态SQL

专栏精选

引入Mybatis

Mybatis的快速入门

Mybatis的增删改查扩展功能说明

mapper映射的参数和结果

Mybatis复杂类型的结果映射

Mybatis基于注解的结果映射

Mybatis枚举类型处理和类型处理器

再谈动态SQL

Mybatis配置入门

Mybatis行为配置之Ⅰ—缓存

Mybatis行为配置之Ⅱ—结果相关配置项说明

Mybatis行为配置之Ⅲ—其他行为配置项说明

Mybatis行为配置之Ⅳ—日志

Mybatis整合Spring详解

Mybatis插件入门

Mybatis专栏代码资源

文章目录

  • 专栏精选
  • 摘要
  • 引言
  • 正文
    • 动态sql标签
      • if
      • choose...when...otherwise
      • where、set
      • trim
      • foreach
      • script
    • 动态sql API
      • 通过类名和方法名定位SQL
      • 通过方法名定位SQL
      • 自动定位SQL
  • 总结

摘要

在这篇文章中,我们将深入Mybatis动态SQL的世界,了解动态SQL标签和动态sqlAPI的基本方法,其中的很多观点或内容都能在一定程度上让我们的开发之旅更加轻松方便,这是一个菜鸟提升技术能力,老鸟巩固基础知识的好机会。准备好开启今天的神奇之旅了吗?

引言

大家好,我是奇迹老李,一个专注于分享开发经验和基础教程的博主。欢迎来到我的频道,这里汇聚了汇集编程技巧、代码示例和技术教程,欢迎广大朋友们点赞评论提出意见,重要的是点击关注喔 🙆,期待在这里与你共同度过美好的时光🕹️,今天要和大家分享的内容是再谈动态SQL。做好准备,Let’s go🚎🚀

正文

首图

在引入Mybatis一文中我们提到,jdbc对于过长,过复杂,多条件查询的无力感,Mybatis提供动态SQL这一特性解决拼接SQL语句的痛点。在之前的文章中我们已经简单介绍过动态SQL的一些特性,如

  1. 条件语句if、choose…when…otherwise
  2. 循环语句foreach
  3. sql条件语句where、set

除此之外,动态SQL还包含以下几种特性

  1. 扩展语句trim、bind、script

  2. 动态sql API

动态sql标签

if

<if test="null != appName and ''.toString() != appName">and app_name like concat('%',#{appName},'%')</if>  
<if test="null != authType and ''.toString() != authType">and auth_type = #{authType}</if>  
<if test="null != startDate and '' != startDate">and create_date >= #{startDate}</if>  
<if test="null != endDate and '' != endDate">and create_date &lt;= #{endDate}</if>

choose…when…otherwise

mybatis映射文件中的 if…else

<choose>  <when test="id != null and id > 0">id=#{id}</when>  <when test="id <= 0">is_del='0'</when><otherwise>id='1'</otherwise>  
</choose>

java代码的同义改写

Intege id=...;
if(id != null && id >0){//id=#{id}
}else if(id <=0){//is_del='0'
}else{//id='1'
}

where、set

where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
—— Mybatis官方文档

<!--如果满足if条件,and auth_type = #{authType}中的“and ”将会被删除,并在前边添加“where ”,其结果是-->
<!--where auth_type = #{authType}-->
select * from app_test
<where>  <if test="null != authType and ''.toString() != authType">and auth_type = #{authType}</if>  
</where>

set 元素用于更新(update)语句中的set部分,和where一样,set的子元素返回的结果结尾如果有“, ”,set元素也会自动将其去除

<!--如果满足if条件,app_name = #{appName},中的“,”会被删除,其他的“,”不会删除,并在语句之前添加“set ”,其结果是-->
<!--update app_test set app_code = #{appCode},app_name = #{appName} where id=#{id}-->
update app_test  
<set>  <if test="appCode != null and '' != appCode">app_code = #{appCode},</if><if test="appName != null and '' != appName">app_name = #{appName},</if>
</set>
where id=#{id}

trim

trim元素中可以自定义子句应该忽略的内容、和应该添加的内容,where和set标签的功能都能通过trim实现

trim实现where的功能

<!--prefix属性表示将要给子句添加的前缀,prefixOverrides属性表示子句如果出现这样的开头将其忽略-->
select * from app_test
<trim prefix="WHERE" prefixOverrides="AND |OR "><if test="null != authType and ''.toString() != authType">AND auth_type = #{authType}</if>  
</trim>

trim实现set的功能

<!--suffixOverrides属性表示子句如果出现这样的结尾将其忽略-->
update app_test  
<trim prefix="SET" suffixOverrides=","><if test="appCode != null and '' != appCode">app_code = #{appCode},</if><if test="appName != null and '' != appName">app_name = #{appName},</if>
</trim>
where id=#{id}

trim标签属性详解

序号属性名效果说明
1prefix前缀
2suffix后缀
3prefixOverrides将被删除的前缀
4suffixOverrides将被删除的后缀

由此可见,以上的set内容可以写成如下形式

update upp_test set 
<trim suffix="where id=#{id}" suffixOverrides=","><if test="appCode != null and '' != appCode">app_code = #{appCode},</if><if test="appName != null and '' != appName">app_name = #{appName},</if>
</trim>

相应的where内容也可以写成如下形式

select * from app_test 
<trim prefix="where " prefixOverrides="AND |OR "><if test="null != authType and ''.toString() != authType">AND auth_type = #{authType}</if>  
</trim>

foreach

foreach标签用来遍历集合数据

foreach标签的使用方式如下:

insert into app_test(app_name,app_code,auth_type,create_date,creator) values
<foreach collection="list" separator="," item="entity" index="index" open="" close="">  (#{entity.appName},#{entity.appCode},#{entity.authType},#{entity.createDate},#{entity.creator})  
</foreach>

foreach标签的属性说明

序号属性名属性说明
1collection集合数据的参数名称
2index集合数据的索引方式,一般默认为index
3item集合内部的元素命名,类似for(T t,List<T>)中的t
4open左侧需要添加的字符
5close右侧需要添加的字符

script

Mybatis支持通过注解的形式编写sql语句,主要通过@Select,@Insert,@Update,@Delete几个注解实现,示例如下

@Select("select * from app_test where auth_type=#{type}")  
List<AppTestEntity> queryList(@Param("type") String type);

这样就省略了创建xml映射文件的工作,但是这样有一个缺点,就是不方便编写动态sql,这时可以使用script标签

public interface ApplicationRepository {@Update({  "<script>",  "update app_test",  "<set>",  "<if test=\"appStatus != null and appStatus != '' \">app_status=#{appStatus},</if>",  "</set>",  "where id=#{id}",  "</script>"  })  int updateByScript(AppTestEntity app);
}

这里需要注意,在字符串中使用 " 双引号字符,需要使用 \ 符号转义,如上例所示

动态sql API

除了通过映射文件使用动态sql的方式之外,Mybatis还提供了基于JavaAPI实现动态sql的方案。(这种方法可以弥补script标签的不足)

通过类名和方法名定位SQL

这里我们针对AppTest对象的条件查询进行改造

public interface ApplicationRepository {//此注解用于标注动态sql生成的类,方法名称@SelectProvider(type = ApplicationSqlProvider.class,method = "queryAppFunc")  List<AppTestEntity> queryAppProvider(AppSearchVo param);
}//动态sql生成类
//这个类名称和方法名称需要和@SelectProvider注解标注的类型和方法名称相对应
package top.sunyog.mybatis.provider;  import org.apache.ibatis.jdbc.SQL;  
import top.sunyog.common.entity.AppSearchVo;  public class ApplicationSqlProvider {  public static String queryAppFunc(AppSearchVo param){  SQL sql = new SQL() {//静态代码块{  SELECT("*");  FROM("app_test");  if (param.getAppName()!=null && !"".equals(param.getAppName())) {  WHERE("app_name like concat('%',#{appName},'%')");  }  if (param.getAuthType()!=null && !"".equals(param.getAuthType())){  WHERE("auth_type = #{authType}");  }  if (param.getStartDate() != null){  WHERE("create_date >= #{startDate}");  }  if (param.getEndDate() != null){  WHERE("create_date <= #{endDate}");  }  }};  return sql.toString();  }  
}

功能测试类

public class ApplicationService extends MybatisService<ApplicationRepository>{@Override  public void doService() {  ApplicationRepository mapper = super.getMapper(ApplicationRepository.class);  this.testSelectProvider(mapper);  }private void testSelectProvider(ApplicationRepository mapper){  AppSearchVo vo = new AppSearchVo();  vo.setAppName("1");  vo.setAuthType("2");  vo.setStartDate(LocalDateTime.of(2023,11,1,12,10));  vo.setEndDate(LocalDateTime.of(2023,11,3,12,10));  List<AppTestEntity> list = mapper.queryAppProvider(vo);  list.forEach(System.out::println);  }
}

通过方法名定位SQL

除了通过 @SelectProvider注解直接指定类和方法之外,还可以只指定类,但这种方式需要保证Mapper接口的方法名称和 Provider类的方法名称一一对应。

//mapper接口
@SelectProvider(type = ApplicationSqlProvider.class)  
List<AppTestEntity> queryAppProvider(AppSearchVo param);//provider类
public class ApplicationSqlProvider implements ProviderMethodResolver {  public static String queryAppProvider(AppSearchVo param){...}
}

使用这种方式需要保证两点:

  1. 方法名称相同
  2. provider类实现 ProviderMethodResolver 接口

自动定位SQL

通过配置默认的 SqlProvider类,可以将所有的 @*Provider 定位到同一个类中,只要保证 mapper接口的方法名称和 Provider类的方法名称相同即可

配置说明

<configuration>  <properties resource="..."/><settings>  <!--设定默认的 sql provider--><setting name="defaultSqlProviderType" value="top.sunyog.mybatis.provider.ApplicationSqlProvider"/>  </settings>...
</configuration>

mapper接口和provider类

//mapper接口
@SelectProvider  
List<AppTestEntity> queryAppProvider(AppSearchVo param);//provider类
public class ApplicationSqlProvider implements ProviderMethodResolver {  public static String queryAppProvider(AppSearchVo param){...}
}

总结

在MyBatis中,动态SQL是非常有用的特性,它们允许开发者根据不同的条件构建动态的SQL查询,以及更加灵活地生成SQL查询。动态SQL标签提供了灵活的逻辑控制,使我们可以根据不同的条件动态地添加或删除SQL片段。动态SQL API允许我们以编码的方式使用动态SQL,这就相当于在动态SQL之上引入了更加灵活的逻辑处理功能。

你是否曾经使用过MyBatis的动态SQL标签或相关API?如果有,请在评论区分享你的使用经验和心得。如果你还没有使用过这些特性,现在可以用起来了。


📩 联系方式
邮箱:qijilaoli@foxmail.com

❗版权声明
本文为原创文章,版权归作者所有。未经许可,禁止转载。更多内容请访问奇迹老李的博客首页

相关文章:

再谈动态SQL

专栏精选 引入Mybatis Mybatis的快速入门 Mybatis的增删改查扩展功能说明 mapper映射的参数和结果 Mybatis复杂类型的结果映射 Mybatis基于注解的结果映射 Mybatis枚举类型处理和类型处理器 再谈动态SQL Mybatis配置入门 Mybatis行为配置之Ⅰ—缓存 Mybatis行为配置…...

【数据结构】树

一.二叉树的基本概念和性质&#xff1a; 1.二叉树的递归定义&#xff1a; 二叉树或为空树&#xff0c;或是由一个根结点加上两棵分别称为左子树和右子树的、互不相交的二叉树组成 2.二叉树的特点&#xff1a; &#xff08;1&#xff09;每个结点最多只有两棵子树&#xff0…...

【Midjourney】AI绘画新手教程(一)登录和创建服务器,生成第一幅画作

一、登录Discord 1、访问Discord官网 使用柯學尚网&#xff08;亲测非必须&#xff0c;可加快响应速度&#xff09;访问Discord官方网址&#xff1a;https://discord.com 选择“在您的浏览器中打开Discord” 然后&#xff0c;注册帐号、购买套餐等&#xff0c;在此不做缀述。…...

对比 PyTorch 和 TensorFlow:选择适合你的深度学习框架

目录 引言 深度学习在各行业中的应用 PyTorch 和 TensorFlow 简介 PyTorch&#xff1a;简介与设计理念 发展历史和背景 主要特点和设计理念 TensorFlow&#xff1a;简介与设计理念 发展历史和背景 主要特点和设计理念 PyTorch 和 TensorFlow 的重要性 Pytorch对比Te…...

Oracle笔记-查看表已使用空间最大空间

目前以Oracle18c为例&#xff0c;主要是查这个表USER_SEGMENTS。 在 Oracle 18c 数据库中&#xff0c;USER_SEGMENTS 是一个系统表&#xff0c;用于存储当前用户&#xff08;当前会话&#xff09;拥有的所有段的信息。段是 Oracle 中分配存储空间的逻辑单位&#xff0c;用于存…...

大数据HCIE成神之路之特征工程——特征选择

特征选择 1.1 特征选择 - Filter方法1.1.1 实验任务1.1.1.1 实验背景1.1.1.2 实验目标1.1.1.3 实验数据解析1.1.1.4 实验思路 1.1.2 实验操作步骤 1.2 特征选择 - Wrapper方法1.2.1 实验任务1.2.1.1 实验背景1.2.1.2 实验目标1.2.1.3 实验数据解析1.2.1.4 实验思路 1.2.2 实验操…...

python 正则-常见题目

1、邮箱 print(re.findall(r[\w-][\w-]\.[\w-], weidianqq.com))2、身份证号 xxxxxx yyyy MM dd 375 0 十八位 print(re.findall(r(?:18|19|(?:[23]\d))\d{2}, 2010)) # 年print(re.findall(r(?:0[1-9])|10|11|12, 11)) # 月print(re.findall(r(?:[0-2][1-9])|10|20|30|3…...

解析:Eureka的工作原理

Eureka是Netflix开源的一个基于REST的的服务发现注册框架&#xff0c;它遵循了REST协议&#xff0c;提供了一套简单的API来完成服务的注册和发现。Eureka能够帮助分布式系统中的服务提供者自动将自身注册到注册中心&#xff0c;同时也能够让服务消费者从注册中心发现服务提供者…...

RecyclerView 与 ListView 区别和使用

前置知识&#xff1a;ListView基本用法与性能提升 RecyclerView 与 ListView 区别 RecyclerView 需要设置布局&#xff08;LinearLayoutManager、GridLayoutManager、StaggeredGridLayoutManager&#xff09; recyclerView?.layoutManager LinearLayoutManager(activity) …...

力扣232. 用栈实现队列

题目 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作&#xff08;push、pop、peek、empty&#xff09;&#xff1a; 实现 MyQueue 类&#xff1a; void push(int x) 将元素 x 推到队列的末尾int pop() 从队列的开头移除并返回元素int peek() 返回队列开…...

这个方法可以让你把图片无损放大

随着数字技术的不断发展&#xff0c;照片无损放大已经成为了摄影领域中的一项重要技术。照片无损放大能够让摄影师在不损失细节和画质的情况下&#xff0c;将照片放大到更大的尺寸&#xff0c;从而让观众能够更加清晰地欣赏到照片中的每一个细节。 今天推荐的这款软件主要是通…...

Springboot整合Elastic-job

一 概述 Elastic-Job 最开始只有一个 elastic-job-core 的项目&#xff0c;定位轻量级、无中心化&#xff0c;最核心的服务就是支持弹性扩容和数据分片&#xff01;从 2.X 版本以后&#xff0c;主要分为 Elastic-Job-Lite 和 Elastic-Job-Cloud 两个子项目。esjbo官网地址 Ela…...

VsCode的介绍和入门

目录 ​编辑 介绍 我应该切换到 VS Code 吗&#xff1f;为什么&#xff1f; 入门 Explorer 搜索 源代码控制 调试器 扩展 终点站 命令面板 主题 定制化 不错的配置选项 最适合编码的字体 工作空间 编辑 智能感知 代码格式化 错误和警告 键盘快捷键 键位图…...

C++:自创小游戏

欢迎来玩&#xff0c;每次都有不一样的结果。 长达142行。 #include<bits/stdc.h> #include<windows.h> #define random(a,b) (rand()%(b-a1)a) using namespace std; int main(){int n;cout<<"输1~10,越小越好,不告诉你有什么用&#xff0c;当然也可…...

AIGC带给开发者的冲击

未来会有两种开发者&#xff0c;一种是会使用AIGC工具的开发者另一种是不会使用AIGC的开发者&#xff0c;AIGC的出现提高了开发效率和代码质量&#xff0c;对开发者意味着需要不断学习和适应新的技术和工作范式&#xff0c;开发者可以把更多的精力放在高级抽象的定义以及更高维…...

利用蚁剑钓鱼上线CS

前言 中国蚁剑使用Electron构建客户端软件&#xff0c;Electron实现上用的是Node.js&#xff0c;并且Node.js能执行系统命令&#xff0c;故可以利用蚁剑的webshell页面嵌入js来直接执行命令&#xff0c;进而钓鱼来上线CS。&#xff08;类似Goby&#xff0c;Goby也是使用Electr…...

宣传照(私密)勿转发

精美的海报通常都是由UI进行精心设计的&#xff0c;现在有100 件商品需要进行宣传推广&#xff0c;如果每个商品都出一张图显然是不合理的&#xff0c;且商品信息各异。因此需要通过代码的形式生成海报。对此&#xff0c;我也对我宣传一波&#xff0c;企图实现我一夜暴富的伟大…...

【Spring】19 AOP介绍及实例详解

文章目录 1. 定义1&#xff09;什么意思呢&#xff1f;2&#xff09;如何解决呢&#xff1f; 2. 基本概念1&#xff09;切面&#xff08;Aspect&#xff09;2&#xff09;切点&#xff08;Pointcut&#xff09;3&#xff09;通知&#xff08;Advice&#xff09;4&#xff09;连…...

ES(Elasticsearch)的基本使用

一、常见的NoSQL解决方案 1、redis Redis是一个基于内存的 key-value 结构数据库。Redis是一款采用key-value数据存储格式的内存级NoSQL数据库&#xff0c;重点关注数据存储格式&#xff0c;是key-value格式&#xff0c;也就是键值对的存储形式。与MySQL数据库不同&#xff0…...

【JVM面试题】Java中的静态方法为什么不能调用非静态方法

昨晚京东大佬勇哥在群里分享了一道他新创的JVM面试题&#xff0c;我听完后觉得还挺有意思的&#xff0c;分享给大家 小佬们先别急着看我的分析&#xff0c;先自己想想答案 你是不是想说 因为静态方法是属于类的&#xff0c;而非静态方法属于实例对象 哈&#xff0c;有人这样回答…...

浅谈 React Hooks

React Hooks 是 React 16.8 引入的一组 API&#xff0c;用于在函数组件中使用 state 和其他 React 特性&#xff08;例如生命周期方法、context 等&#xff09;。Hooks 通过简洁的函数接口&#xff0c;解决了状态与 UI 的高度解耦&#xff0c;通过函数式编程范式实现更灵活 Rea…...

Python|GIF 解析与构建(5):手搓截屏和帧率控制

目录 Python&#xff5c;GIF 解析与构建&#xff08;5&#xff09;&#xff1a;手搓截屏和帧率控制 一、引言 二、技术实现&#xff1a;手搓截屏模块 2.1 核心原理 2.2 代码解析&#xff1a;ScreenshotData类 2.2.1 截图函数&#xff1a;capture_screen 三、技术实现&…...

.Net框架,除了EF还有很多很多......

文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件

在选煤厂、化工厂、钢铁厂等过程生产型企业&#xff0c;其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进&#xff0c;需提前预防假检、错检、漏检&#xff0c;推动智慧生产运维系统数据的流动和现场赋能应用。同时&#xff0c;…...

汽车生产虚拟实训中的技能提升与生产优化​

在制造业蓬勃发展的大背景下&#xff0c;虚拟教学实训宛如一颗璀璨的新星&#xff0c;正发挥着不可或缺且日益凸显的关键作用&#xff0c;源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例&#xff0c;汽车生产线上各类…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!

5月28日&#xff0c;中天合创屋面分布式光伏发电项目顺利并网发电&#xff0c;该项目位于内蒙古自治区鄂尔多斯市乌审旗&#xff0c;项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站&#xff0c;总装机容量为9.96MWp。 项目投运后&#xff0c;每年可节约标煤3670…...

Spring AI 入门:Java 开发者的生成式 AI 实践之路

一、Spring AI 简介 在人工智能技术快速迭代的今天&#xff0c;Spring AI 作为 Spring 生态系统的新生力量&#xff0c;正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务&#xff08;如 OpenAI、Anthropic&#xff09;的无缝对接&…...

今日科技热点速览

&#x1f525; 今日科技热点速览 &#x1f3ae; 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售&#xff0c;主打更强图形性能与沉浸式体验&#xff0c;支持多模态交互&#xff0c;受到全球玩家热捧 。 &#x1f916; 人工智能持续突破 DeepSeek-R1&…...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)

考察一般的三次多项式&#xff0c;以r为参数&#xff1a; p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]&#xff1b; 此多项式的根为&#xff1a; 尽管看起来这个多项式是特殊的&#xff0c;其实一般的三次多项式都是可以通过线性变换化为这个形式…...