再谈动态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的一些特性,如
- 条件语句if、choose…when…otherwise
- 循环语句foreach
- sql条件语句where、set
除此之外,动态SQL还包含以下几种特性
-
扩展语句trim、bind、script
-
动态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 <= #{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标签属性详解
序号 | 属性名 | 效果说明 |
---|---|---|
1 | prefix | 前缀 |
2 | suffix | 后缀 |
3 | prefixOverrides | 将被删除的前缀 |
4 | suffixOverrides | 将被删除的后缀 |
由此可见,以上的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标签的属性说明
序号 | 属性名 | 属性说明 |
---|---|---|
1 | collection | 集合数据的参数名称 |
2 | index | 集合数据的索引方式,一般默认为index |
3 | item | 集合内部的元素命名,类似for(T t,List<T>) 中的t |
4 | open | 左侧需要添加的字符 |
5 | close | 右侧需要添加的字符 |
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){...}
}
使用这种方式需要保证两点:
- 方法名称相同
- 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行为配置…...
【数据结构】树
一.二叉树的基本概念和性质: 1.二叉树的递归定义: 二叉树或为空树,或是由一个根结点加上两棵分别称为左子树和右子树的、互不相交的二叉树组成 2.二叉树的特点: (1)每个结点最多只有两棵子树࿰…...
【Midjourney】AI绘画新手教程(一)登录和创建服务器,生成第一幅画作
一、登录Discord 1、访问Discord官网 使用柯學尚网(亲测非必须,可加快响应速度)访问Discord官方网址:https://discord.com 选择“在您的浏览器中打开Discord” 然后,注册帐号、购买套餐等,在此不做缀述。…...
对比 PyTorch 和 TensorFlow:选择适合你的深度学习框架
目录 引言 深度学习在各行业中的应用 PyTorch 和 TensorFlow 简介 PyTorch:简介与设计理念 发展历史和背景 主要特点和设计理念 TensorFlow:简介与设计理念 发展历史和背景 主要特点和设计理念 PyTorch 和 TensorFlow 的重要性 Pytorch对比Te…...
Oracle笔记-查看表已使用空间最大空间
目前以Oracle18c为例,主要是查这个表USER_SEGMENTS。 在 Oracle 18c 数据库中,USER_SEGMENTS 是一个系统表,用于存储当前用户(当前会话)拥有的所有段的信息。段是 Oracle 中分配存储空间的逻辑单位,用于存…...
大数据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的的服务发现注册框架,它遵循了REST协议,提供了一套简单的API来完成服务的注册和发现。Eureka能够帮助分布式系统中的服务提供者自动将自身注册到注册中心,同时也能够让服务消费者从注册中心发现服务提供者…...
RecyclerView 与 ListView 区别和使用
前置知识:ListView基本用法与性能提升 RecyclerView 与 ListView 区别 RecyclerView 需要设置布局(LinearLayoutManager、GridLayoutManager、StaggeredGridLayoutManager) recyclerView?.layoutManager LinearLayoutManager(activity) …...
力扣232. 用栈实现队列
题目 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty): 实现 MyQueue 类: void push(int x) 将元素 x 推到队列的末尾int pop() 从队列的开头移除并返回元素int peek() 返回队列开…...
这个方法可以让你把图片无损放大
随着数字技术的不断发展,照片无损放大已经成为了摄影领域中的一项重要技术。照片无损放大能够让摄影师在不损失细节和画质的情况下,将照片放大到更大的尺寸,从而让观众能够更加清晰地欣赏到照片中的每一个细节。 今天推荐的这款软件主要是通…...
Springboot整合Elastic-job
一 概述 Elastic-Job 最开始只有一个 elastic-job-core 的项目,定位轻量级、无中心化,最核心的服务就是支持弹性扩容和数据分片!从 2.X 版本以后,主要分为 Elastic-Job-Lite 和 Elastic-Job-Cloud 两个子项目。esjbo官网地址 Ela…...
VsCode的介绍和入门
目录 编辑 介绍 我应该切换到 VS Code 吗?为什么? 入门 Explorer 搜索 源代码控制 调试器 扩展 终点站 命令面板 主题 定制化 不错的配置选项 最适合编码的字体 工作空间 编辑 智能感知 代码格式化 错误和警告 键盘快捷键 键位图…...
C++:自创小游戏
欢迎来玩,每次都有不一样的结果。 长达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,越小越好,不告诉你有什么用,当然也可…...
AIGC带给开发者的冲击
未来会有两种开发者,一种是会使用AIGC工具的开发者另一种是不会使用AIGC的开发者,AIGC的出现提高了开发效率和代码质量,对开发者意味着需要不断学习和适应新的技术和工作范式,开发者可以把更多的精力放在高级抽象的定义以及更高维…...
利用蚁剑钓鱼上线CS
前言 中国蚁剑使用Electron构建客户端软件,Electron实现上用的是Node.js,并且Node.js能执行系统命令,故可以利用蚁剑的webshell页面嵌入js来直接执行命令,进而钓鱼来上线CS。(类似Goby,Goby也是使用Electr…...
宣传照(私密)勿转发
精美的海报通常都是由UI进行精心设计的,现在有100 件商品需要进行宣传推广,如果每个商品都出一张图显然是不合理的,且商品信息各异。因此需要通过代码的形式生成海报。对此,我也对我宣传一波,企图实现我一夜暴富的伟大…...
【Spring】19 AOP介绍及实例详解
文章目录 1. 定义1)什么意思呢?2)如何解决呢? 2. 基本概念1)切面(Aspect)2)切点(Pointcut)3)通知(Advice)4)连…...
ES(Elasticsearch)的基本使用
一、常见的NoSQL解决方案 1、redis Redis是一个基于内存的 key-value 结构数据库。Redis是一款采用key-value数据存储格式的内存级NoSQL数据库,重点关注数据存储格式,是key-value格式,也就是键值对的存储形式。与MySQL数据库不同࿰…...
【JVM面试题】Java中的静态方法为什么不能调用非静态方法
昨晚京东大佬勇哥在群里分享了一道他新创的JVM面试题,我听完后觉得还挺有意思的,分享给大家 小佬们先别急着看我的分析,先自己想想答案 你是不是想说 因为静态方法是属于类的,而非静态方法属于实例对象 哈,有人这样回答…...
对‘float16_t’的引用有歧义
float16_t 是一个半精度浮点数类型,通常在一些需要高性能和低精度的场合被使用。 如果加了using namespace cv;后,OpenCV库中也有一个名为float16_t的类型定义,与最初的float16_t存在冲突,导致编译失败。 为了解决这个问题&#…...
Windows重装升级Win11系统后 恢复Mysql数据
背景 因为之前电脑硬盘出现问题,换了盘重装了系统,项目的数据库全部没了,还好之前的Mysql是安装在的D盘里,还有留存文件 解决办法 1.设置环境变量 我的路径是 D:\SoftWare\Application\mysql-5.7.35-winx64 此电脑右键属性 …...
MySQL之四大引擎、账号管理以及建库
目录 数据库存储引擎 简介 存储引擎得查看 support字段说明 InnoDB MyISAM MEMORY Archive 数据库管理 元数据库简介 元数据库分类 相关操作 MySQL库 数据表管理 三大范式 基本数据类型 优化原则 整形 实数 字符串 text&blob 日期类型 选中标识符 数…...
shell编程——查找局域网内存活主机
题目要求:写一个shell脚本,探测局域网内存活主机 首先,我们的思路是在循环中不断ping主机,然后根据ping的结果来判断主机是否存活 本题中ping语句如下: ping -c 3 -i 0.3 -W 1 192.168.1.1 解释一下参数࿱…...
python django 个人记账管理系统
python django 个人记账管理系统。 功能:登录,新用户注册,个人信息修改,收入,支出记录,收入记账管理,支出记账管理,收入,支出统计 技术:python django&…...
C#的Char 结构的方法之IsLetterOrDigit()
目录 一、Char 结构 二、Char.IsLetterOrDigit 方法 1.定义 2.重载 3.示例 4.IsLetterOrDigit(Char) 5.IsLetterOrDigit(String, Int32) 一、Char 结构方法 CompareTo(Char)将此实例与指定的 Char 对象进行比较,并指示此实例在排序顺序中是位于指定的 Char …...
配置Docker私有仓库
# 打开要修改的文件 vi /etc/docker/daemon.json # 添加内容: "insecure-registries":["http://自己服务器的ip地址:设置的端口号"] # 重加载 systemctl daemon-reload # 重启docker systemctl restart docker在自己设定的文件夹内使用DockerCo…...
计算机网络-动态路由
网络层协议:ip,ospf,rip,icmp共同组成网络层体系 ospf用于自治系统内部。 一个路由器或者网关需要能够支持多个不同的路由协议,以适应不同的网络环境。特别是在连接不同自治系统的边缘路由器或边界网关的情况下&#…...
光耀未来 第一届能源电子产业创新大赛太阳能光伏赛道决赛在宜宾举行
1月3日,第一届能源电子产业创新大赛太阳能光伏赛道决赛在宜宾盛大举行,本次比赛吸引了全国范围内的光伏行业顶尖人才和创新团队参与。 为深入贯彻《关于推动能源电子产业发展的指导意见》,推动我国能源电子产业升级,工业和信息化部…...
【小沐学NLP】Python实现TF-IDF算法(nltk、sklearn、jieba)
文章目录 1、简介1.1 TF1.2 IDF1.3 TF-IDF2.1 TF-IDF(sklearn)2.2 TF-IDF(nltk)2.3 TF-IDF(Jieba)2.4 TF-IDF(python) 结语 1、简介 TF-IDF(term frequency–inverse document frequency)是一种用于信息检索与数据挖掘的常用加权技术。TF是词频(Term Fr…...
分析网络营销的特点/沈阳seo优化排名公司
ppt转pdf一般人都会去网上搜,今天我想把ppt转pdf,一搜百度就是一堆软件跟广告,看着就™恶心。 今天我找到了ppt转pdf的方法,以后不用去在苦恼这个事情了,希望能帮到你鸭。 打开需要转换的ppt点击文件 点击导出 点击创…...
做足彩网站推广/东莞网络营销全网推广
大家好,我是 CUGGZ。今天来分享 12 个 yyds 的微信小程序开源项目,速速收藏!全文概览:wechat-app-mall:微信小程序商城;Vant Weapp:小程序 UI 组件库;iView Weapp:小程序…...
游戏怎么做充值网站/国家认可的赚钱软件
前端字体网站收藏 Fonts 提供免费字体以及基于字体的工具的网站 Github项目地址 Design Resources For Developers 网站 描述Google Fonts包含约1000个免费授权的字体家族库DaFont免费可下载字体的存档Use & Modify包含优美、高雅、朋克、专业、不…...
做三盛石材网站的公司/灰色词排名接单
转载自:https://www.cnblogs.com/bekeyuan123/p/6891875.html 数组的定义: // 3种定义方式int[] arr new int[5];int[] arr1 {1,2,3,4,5};int[] nums new int[]{1, 2, 3};long[] arr2 new long[6];String[] strs new String[5];// 数组可以存储引用…...
做网站租用服务器/成都seo优化公司排名
SELECT r.Studentno AS "李"同学学号,studentname AS 姓名,StudentResult AS 成绩 FROM result AS r INNER JOIN student AS s ON r.StudentNos.StudentNo AND studentname LIKE CONCAT(李,%) 转载于:https://www.cnblogs.com/Suaron/p/9781731.html...
建设银行网站认证/中国联通腾讯
<view classitem bindtaponCountryTab data-idx4>1)bindtap属性用来设置控件需要绑定的函数,函数用单引号括起来;、2)函数定义的位置在 “../xxx.js” 文件里面;、3)转载于:https://www.cnblogs.com/…...