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

【MyBatis源码】SQL 语句构建器AbstractSQL

文章目录

  • 介绍
  • org.apache.ibatis.jdbc.SQL
  • SQL类使用示例
  • @SelectProvider搭配动态SQL
  • AbstractSQL类源码分析

介绍

当我们需要使用Statement对象执行SQL时,SQL语句会嵌入Java代码中。SQL语句比较复杂时,我们可能会在代码中对SQL语句进行拼接,查询条件不固定时,还需要根据不同条件拼接不同的SQL语句。在MyBatis中已经为我们提供了这类开发工具类。
MyBatis 中的 AbstractSQL 类是 MyBatis 提供的一个用于构建动态 SQL 语句的工具类。它的主要用途是帮助开发者更灵活、优雅地拼接复杂的 SQL 语句,尤其是在需要根据条件生成不同的 SQL 语句时,可以减少手动拼接 SQL 字符串的繁琐工作,并提高代码的可读性和维护性。
在日常开发中,尤其是当涉及到复杂查询、更新、插入时,AbstractSQL 可以用于生成动态 SQL。其用途主要包括以下几个方面:

动态条件查询:根据不同的条件拼接 SELECT 语句。
动态插入:根据传入的实体类生成不同的 INSERT 语句。
动态更新:根据条件生成 UPDATE 语句,只更新有值的字段。
动态删除:根据条件拼接 DELETE 语句。
AbstractSQL 的核心思想是通过链式调用的方式构建 SQL 语句,这类似于构建器模式(Builder Pattern)。

org.apache.ibatis.jdbc.SQL

public class SQL extends AbstractSQL<SQL> {@Overridepublic SQL getSelf() {return this;}
}

SQL类继承了AbstractSQL,在日常开发中一般使用SQL类。

SQL类使用示例

【动态构建 SELECT 查询】

  @Testpublic void testSelectSQL() {String orgSql = "SELECT P.ID, P.USERNAME, P.PASSWORD, P.FULL_NAME, P.LAST_NAME, P.CREATED_ON, P.UPDATED_ON\n" +"FROM PERSON P, ACCOUNT A\n" +"INNER JOIN DEPARTMENT D on D.ID = P.DEPARTMENT_ID\n" +"INNER JOIN COMPANY C on D.COMPANY_ID = C.ID\n" +"WHERE (P.ID = A.ID AND P.FIRST_NAME like ?) \n" +"OR (P.LAST_NAME like ?)\n" +"GROUP BY P.ID\n" +"HAVING (P.LAST_NAME like ?) \n" +"OR (P.FIRST_NAME like ?)\n" +"ORDER BY P.ID, P.FULL_NAME";String newSql = new SQL() {{SELECT("P.ID, P.USERNAME, P.PASSWORD, P.FULL_NAME");SELECT("P.LAST_NAME, P.CREATED_ON, P.UPDATED_ON");FROM("PERSON P");FROM("ACCOUNT A");INNER_JOIN("DEPARTMENT D on D.ID = P.DEPARTMENT_ID");INNER_JOIN("COMPANY C on D.COMPANY_ID = C.ID");WHERE("P.ID = A.ID");WHERE("P.FIRST_NAME like ?");OR();WHERE("P.LAST_NAME like ?");GROUP_BY("P.ID");HAVING("P.LAST_NAME like ?");OR();HAVING("P.FIRST_NAME like ?");ORDER_BY("P.ID");ORDER_BY("P.FULL_NAME");}}.toString();assertEquals(orgSql, newSql);}
// 匿名内部类风格
public String deletePersonSql() {return new SQL() {{DELETE_FROM("PERSON");WHERE("ID = #{id}");}}.toString();
}// Builder / Fluent 风格
public String insertPersonSql() {String sql = new SQL().INSERT_INTO("PERSON").VALUES("ID, FIRST_NAME", "#{id}, #{firstName}").VALUES("LAST_NAME", "#{lastName}").toString();return sql;
}// 动态条件(注意参数需要使用 final 修饰,以便匿名内部类对它们进行访问)
public String selectPersonLike(final String id, final String firstName, final String lastName) {return new SQL() {{SELECT("P.ID, P.USERNAME, P.PASSWORD, P.FIRST_NAME, P.LAST_NAME");FROM("PERSON P");if (id != null) {WHERE("P.ID like #{id}");}if (firstName != null) {WHERE("P.FIRST_NAME like #{firstName}");}if (lastName != null) {WHERE("P.LAST_NAME like #{lastName}");}ORDER_BY("P.LAST_NAME");}}.toString();
}public String deletePersonSql() {return new SQL() {{DELETE_FROM("PERSON");WHERE("ID = #{id}");}}.toString();
}public String insertPersonSql() {return new SQL() {{INSERT_INTO("PERSON");VALUES("ID, FIRST_NAME", "#{id}, #{firstName}");VALUES("LAST_NAME", "#{lastName}");}}.toString();
}public String updatePersonSql() {return new SQL() {{UPDATE("PERSON");SET("FIRST_NAME = #{firstName}");WHERE("ID = #{id}");}}.toString();
}

相关官方文档:
https://mybatis.org/mybatis-3/zh_CN/statement-builders.html

@SelectProvider搭配动态SQL

@SelectProvider 注解是 MyBatis 提供的一种动态 SQL 语句生成方式,用于将复杂的查询逻辑封装在 Java 方法中,而不是直接在 Mapper 接口的方法上书写固定的 SQL 语句。通过 @SelectProvider 注解,MyBatis 可以根据实际情况动态生成 SQL,这使得 SQL 语句更加灵活和可维护。
@SelectProvider 的基本语法

@SelectProvider(type = SQLProviderClass.class, method = "methodName")
List<ResultType> selectMethod(参数);

type:指定提供 SQL 语句的类(通常称为 Provider 类)。
method:指定 Provider 类中的方法名称,该方法用于动态生成 SQL。
selectMethod:Mapper 接口中的方法,最终会执行 methodName 返回的 SQL 语句。

这个注解和@SELECT的区别在于@SelectProvider 注解可以中参数SQLProviderClass可以搭配SQL动态语句类关联SQL。

  @SelectProvider(type = UserSqlProvider.class, method = "buildSelectSql")List<Map<String, Object>> selectUsers(Map<String, Object> params);
public class UserSqlProvider {public String buildSelectSql(Map<String, Object> params) {return new SQL() {{SELECT("*");FROM("t_user");if (params.get("name") != null) {WHERE("name = #{name}");}if (params.get("age") != null) {WHERE("age = #{age}");}ORDER_BY("id DESC");}}.toString();}
}

测试类:

  /*** 测试@SelectProvider使用*/@Testpublic void test6() throws Exception {InputStream resource = Resources.getResourceAsStream(MybatisTest.class.getClassLoader(), "mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resource);Configuration configuration = sqlSessionFactory.getConfiguration();// 手动注册mapperconfiguration.addMapper(UserMapper.class);SqlSession sqlSession = sqlSessionFactory.openSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);Map<String, Object> params = new HashMap<>();params.put("name", "zhangSan");params.put("age", 18);List<Map<String, Object>> res = mapper.selectUsers(params);System.out.println(res);}

在这里插入图片描述

AbstractSQL类源码分析

SQL继承至AbstractSQL类,只重写了该类的getSelf()方法,所有的功能由AbstractSQL类完成,AbstractSQL类中维护了一个SQLStatement内部类的实例和一系列前面提到过的构造SQL语句的方法,例如SELECT()、UPDATE()等方法。

  public enum StatementType {DELETE, INSERT, SELECT, UPDATE}
  StatementType statementType;List<String> sets = new ArrayList<>();List<String> select = new ArrayList<>();List<String> tables = new ArrayList<>();List<String> join = new ArrayList<>();List<String> innerJoin = new ArrayList<>();List<String> outerJoin = new ArrayList<>();List<String> leftOuterJoin = new ArrayList<>();List<String> rightOuterJoin = new ArrayList<>();List<String> where = new ArrayList<>();List<String> having = new ArrayList<>();List<String> groupBy = new ArrayList<>();List<String> orderBy = new ArrayList<>();List<String> lastList = new ArrayList<>();List<String> columns = new ArrayList<>();List<List<String>> valuesList = new ArrayList<>();boolean distinct;String offset;String limit;LimitingRowsStrategy limitingRowsStrategy = LimitingRowsStrategy.NOP;
 switch (statementType) {case DELETE:answer = deleteSQL(builder);break;case INSERT:answer = insertSQL(builder);break;case SELECT:answer = selectSQL(builder);break;case UPDATE:answer = updateSQL(builder);break;default:answer = null;}

SQLStatement内部类用于描述一个SQL语句,该类中通过StatementType确定SQL语句的类型。SQLStatement类中还维护了一系列的ArrayList属性,当调用SELECT()、UPDATE()等方法时,这些方法的参数内容会记录在这些ArrayList对象中。
AbstrastSQL类重写了toString()方法,该方法中会调用SQLStatement对象的sql()方法生成SQL字符串。这里会根据不同的SQL类型进行不同类型的SQL语句拼接。

   private String selectSQL(SafeAppendable builder) {if (distinct) {sqlClause(builder, "SELECT DISTINCT", select, "", "", ", ");} else {sqlClause(builder, "SELECT", select, "", "", ", ");}sqlClause(builder, "FROM", tables, "", "", ", ");joins(builder);sqlClause(builder, "WHERE", where, "(", ")", " AND ");sqlClause(builder, "GROUP BY", groupBy, "", "", ", ");sqlClause(builder, "HAVING", having, "(", ")", " AND ");sqlClause(builder, "ORDER BY", orderBy, "", "", ", ");limitingRowsStrategy.appendClause(builder, offset, limit);return builder.toString();}
  @Testpublic void testSelectSQL2() {String newSql = new SQL() {{SELECT("name,mobile_no,age");FROM("t_user A");INNER_JOIN("student B on B.name = A.name");WHERE("B.name like ?");OR();WHERE("A.ID = ?");ORDER_BY("A.ID DESC");}}.toString();System.out.println(newSql);}

在这里插入图片描述

相关文章:

【MyBatis源码】SQL 语句构建器AbstractSQL

文章目录 介绍org.apache.ibatis.jdbc.SQLSQL类使用示例SelectProvider搭配动态SQLAbstractSQL类源码分析 介绍 当我们需要使用Statement对象执行SQL时&#xff0c;SQL语句会嵌入Java代码中。SQL语句比较复杂时&#xff0c;我们可能会在代码中对SQL语句进行拼接&#xff0c;查…...

C++OJ_二叉树的层序遍历

✨✨ 欢迎大家来到小伞的大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;C_OJ 小伞的主页&#xff1a;xiaosan_blog 二叉树的层序遍历 102. 二叉树的层序遍历 - 力扣&#xff08;LeetCode&#xff0…...

什么是直方图算法

什么是直方图算法&#xff1f; 直方图算法是一种优化决策树分裂点搜索效率的算法&#xff0c;被广泛应用于像 LightGBM 和 XGBoost 这样的梯度提升决策树框架中。其核心思想是通过将连续特征的取值范围离散化为有限的区间&#xff08;称为 bins&#xff09;&#xff0c;在这些…...

pg_dump -Fc 导出的自定义格式数据库文件 相关操作

实例 将 test.dmp 文件转换为普通SQL内容, 并打印到屏幕 pg_restore -U postgres -Fc -f - test.dump将 test.dmp 文件转换为普通SQL内容, 并输出到 test.sql 文件中 pg_restore -U postgres -Fc -f test.sql -v test.dump备份得到自定义格式的数据库文件(dmp) pg_dump -U…...

Oh My Posh安装

nullSet up your terminalhttps://ohmyposh.dev/docs/installation/windows Git ee oh-my-posh: Windows上的oh-my-zsh&#xff0c;源地址 https://github.com/JanDeDobbeleer/oh-my-posh.git (gitee.com)https://gitee.com/efluent/oh-my-posh...

Node.js——fs模块-文件夹操作

1、借助Node.js的能力&#xff0c;我们可以对文件夹进行创建、读取、删除等操作 2、方法 方法 说明 mkdir/mkdirSync 创建文件夹 readdir/readdirSync 读取文件夹 rmdir/rmdirSync 删除文件夹 3、语法 其余的方法语法类似 本文的分享到此结束&#xff0c;欢迎大家评论区…...

15分钟学 Go 实战项目三 : 实时聊天室(学习WebSocket并发处理)

实时聊天室&#xff1a;学习WebSocket并发处理 目标概述 在本项目中&#xff0c;我们将创建一个实时聊天室&#xff0c;使用Go语言和WebSocket来处理并发消息交流。这将帮助你深入理解WebSocket协议的工作原理以及如何在Go中实现并发处理。 1. 项目需求 功能需求 用户可以…...

架构评估的方法

三种评估方法※ 第一是基于问卷(检查表)的方式,通过问卷调查对系统比较熟悉的相关人员,这种方式主观性很强。 专家问卷评估、用户问卷评估、内部团队问卷评估 第二是基于度量的方式,对系统指标完全量化,基于量化指标评价系统,这种方式需要评估者对系统非常熟悉。 软件质…...

羲和数据集收集器1.0

为了提升问答对的提取能力并完善GUI,我们从以下几个方面进行改进: 增强文本清理和解析能力:确保能够更准确地识别问答对。 支持更多文件格式:除了现有的 .txt, .docx, 和 .pdf,可以考虑支持其他常见格式如 .xlsx 等。 优化GUI设计:提供更友好的用户界面,包括进度条、日…...

ENSP OSPF和BGP引入

路由协议分为&#xff1a;内部网关协议和外部网关协议。内部网关协议用于自治系统内部的路由&#xff0c;包括&#xff1a;RIP和OSPF。外部网关协议用于自治系统之间的路由&#xff0c;包括BGP。内部网关协议和外部网关协议配合来共同完成网络的路由。 BGP:边界网关路由协议(b…...

软件工程 软考

开发大型软件系统适用螺旋模型或者RUP模型 螺旋模型强调了风险分析&#xff0c;特别适用于庞大而复杂的、高风险的管理信息系统的开发。喷泉模型是一种以用户需求为动力&#xff0c;以对象为为驱动的模型&#xff0c;主要用于描述面向对象的软件开发过程。该模型的各个阶段没有…...

证书学习(六)TSA 时间戳服务器原理 + 7 个免费时间戳服务器地址

目录 一、简介1.1 什么是时间戳服务器1.2 名词扩展1.3 用时间戳标记顺序1.4 7 个免费TSA时间戳服务器地址(亲测可用)1.5 RFC 3161 标准二、时间戳原理2.1 时间戳服务工作流程2.2 验证工作流程2.3 举个例子2.4 时间戳原理总结三、代码实现3.1 curl 命令请求时间戳3.2 java 代码…...

NVR设备ONVIF接入平台EasyCVR私有化部署视频平台如何安装欧拉OpenEuler 20.3 MySQL

在当今数字化时代&#xff0c;安防视频监控系统已成为保障公共安全和个人财产安全的重要工具。NVR设备ONVIF接入平台EasyCVR作为一款功能强大的智能视频监控管理平台&#xff0c;它不仅提供了视频远程监控、录像、存储与回放等基础功能&#xff0c;还涵盖了视频转码、视频快照、…...

c中柔性数组

c99中&#xff0c;结构中最后一个元素允许是未知大小的数组&#xff0c;这就叫柔性数组成员。 柔性数组的特点 1.结构中柔性数组前必须至少有一个其他成员 2.sizeof返回的这种结构大小不包括柔性数组的内存 3.包含柔性数组成员的结构用malloc函数进行动态分配&#xff0c;并…...

图像信号处理器(ISP,Image Signal Processor)详解

简介&#xff1a;个人学习分享&#xff0c;如有错误&#xff0c;欢迎批评指正。 图像信号处理器&#xff08;ISP&#xff0c;Image Signal Processor&#xff09; 是专门用于处理图像信号的硬件或处理单元&#xff0c;广泛应用于图像传感器&#xff08;如 CMOS 或 CCD 传感器&a…...

越权访问漏洞

V2Board Admin.php 越权访问漏洞 ## 漏洞描述 V2board面板 Admin.php 存在越权访问漏洞&#xff0c;由于部分鉴权代码于v1.6.1版本进行了修改&#xff0c;鉴权方式变为从Redis中获取缓存判定是否存在可以调用… V2Board Admin.php 越权访问漏洞 漏洞描述 V2board面板 Admin.ph…...

【Ant.designpro】上传图片

文章目录 一、前端二、后端 一、前端 fieldProps:可以监听并且获取到组件输入的内容 action{“/api/upload_image”} 直接调用后端接口 <ProFormUploadButtonlabel{"上传手续图片"}name{"imgs"}action{"/api/upload_image"}max{5} fieldPro…...

为何选择Spring AI Alibaba开发智能客服平台?

0 前言 本文来看如何使用Spring AI Alibaba构建Agent应用。 1 需求 智能客服平台&#xff0c;可帮助用户完成机票预定、问题解答、机票改签、取消等动作&#xff0c;具体要求&#xff1a; 基于 AI 大模型与用户对话&#xff0c;理解用户自然语言表达的需求支持多轮连续对话…...

HiveSQL 中判断字段是否包含某个值的方法

HiveSQL 中判断字段是否包含某个值的方法 在 HiveSQL 中&#xff0c;有时我们需要判断一个字段是否包含某个特定的值。下面将介绍几种常用的方法来实现这个功能。 一、创建示例表并插入数据 首先&#xff0c;我们创建一个名为employee的表&#xff0c;并插入一些示例数据&am…...

Nginx简易配置将内网网站ssh转发到外网

声明&#xff1a;本内容仅供交流学习使用&#xff0c;部署网站上线还需要根据有关规定申请域名以及备案。 背景 在内网的服务器有一个运行的网页&#xff0c;现使用ssh反向代理&#xff0c;将它转发到外网的服务器。 但是外网的访问ip会被ssh反向代理拦截 所以使用Nginx进行…...

React hook之useRef

React useRef 详解 useRef 是 React 提供的一个 Hook&#xff0c;用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途&#xff0c;下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器

——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的​​一体化测试平台​​&#xff0c;覆盖应用全生命周期测试需求&#xff0c;主要提供五大核心能力&#xff1a; ​​测试类型​​​​检测目标​​​​关键指标​​功能体验基…...

STM32+rt-thread判断是否联网

一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

镜像里切换为普通用户

如果你登录远程虚拟机默认就是 root 用户&#xff0c;但你不希望用 root 权限运行 ns-3&#xff08;这是对的&#xff0c;ns3 工具会拒绝 root&#xff09;&#xff0c;你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案&#xff1a;创建非 roo…...

04-初识css

一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...

10-Oracle 23 ai Vector Search 概述和参数

一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI&#xff0c;使用客户端或是内部自己搭建集成大模型的终端&#xff0c;加速与大型语言模型&#xff08;LLM&#xff09;的结合&#xff0c;同时使用检索增强生成&#xff08;Retrieval Augmented Generation &#…...

《C++ 模板》

目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板&#xff0c;就像一个模具&#xff0c;里面可以将不同类型的材料做成一个形状&#xff0c;其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式&#xff1a;templa…...

BLEU评分:机器翻译质量评估的黄金标准

BLEU评分&#xff1a;机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域&#xff0c;衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标&#xff0c;自2002年由IBM的Kishore Papineni等人提出以来&#xff0c;…...

适应性Java用于现代 API:REST、GraphQL 和事件驱动

在快速发展的软件开发领域&#xff0c;REST、GraphQL 和事件驱动架构等新的 API 标准对于构建可扩展、高效的系统至关重要。Java 在现代 API 方面以其在企业应用中的稳定性而闻名&#xff0c;不断适应这些现代范式的需求。随着不断发展的生态系统&#xff0c;Java 在现代 API 方…...