SpringBoot【九】mybatis-plus之自定义sql零基础教学!
一、前言🔥
环境说明:Windows10 + Idea2021.3.2 + Jdk1.8 + SpringBoot 2.3.1.RELEASE
mybatis-plus的基本使用,前两期基本讲的差不多,够日常使用,但是有的小伙伴可能就会抱怨了,若是遇到业务逻辑比较复杂的sql,都使用swagger 进行拆分组装?mybatis-plus动态拼接sql满足单表查询,若是遇到多表关联且条件复杂涉及分组就不是那么的灵活,那有办法满足该种特殊需求么?不好意思,还真有,mybatis-plus也早就预料到了会存在该种需求,便对该特殊有了特殊处理,继续沿用了他的兄弟mybatis自定义sql的功能,没想到吧!
二、如何自定义SQL
接下来我将为大家介绍两种解决方案。一是直接使用mybatis的注解@Select。二是创建.xml文件的形式。
1、使用注解 @Select()
还记得我们创建一整套控制器的时候,有一个文件夹命名为dao,它今天就是为了干这件事的。首先我们现在dao层先创建一个UserMapper,然后定义几个实例接口给大家看看,让大家熟悉怎么接口上加自定义SQL。
- 传参类型为String,Long,Integer等,传参直接使用。
- 使用@Param("xxx")设置参数 即可
- 参数就是使用@Param设置的value值 即可。
代码演示:
@Select("select * from user where id = #{userId}")
UserEntity getUserById(@Param("userId") String userId);
ok!参数设置成功,查询结果一条。

- 传参类型为.class类,比如XxxModel,XxxEntity等。
获取参数就是直接通过你指定的Param的value对象,对象点属性,这样,比如如下指定的是model那要获取model的sex值,那就是model.sex 即可。
代码演示:
@Select("select * from user u left join grade g on u.id = g.student_id where u.sex = #{model.sex} and g.name = #{model.className}")
List<UserEntity> getUsers(@Param("model")QueryUserInfoModel model);
使用postman请求一下,设置好参数。请看返回结果:

- 传参类型为集合类,比如List等。
像这种集合形式,那得就通过xml文件的形式配置啦。
2、使用xxx.xml文件
先新建一个UserMapper.xml 然后指定 mapper namespace 即可。
- 传参类型为String,Long,Integer等,传参直接使用。
持久层UserMapper.java
UserEntity getUserById(@Param("userId") String userId);
UserMapper.xml
<!--根据userId查询--><select id="getUserById" resultType="com.example.demo.Entity.UserEntity">select * from user where id = #{userId}</select>
post测试,结果显而易见。单参数传递,参数名直接用 #{ param } 就可以获取到。

- 若传参类型为class类等,比如QueryUsersModel、UserEntity等。
UserMapper.java 配置如下:
List<UserInfoVo> getUsers(@Param("model")QueryUserInfoModel model);
UserMapper.xml 配置如下:跟你sql语句没多大区别,唯独就是参数获取方式,这个大家得注意一下。
<!--根据性别和班级名称查询-->
<select id="getUsers" resultMap="BaseResultMap">select u.name as name,g.name as className from user u left join grade g on u.id = g.student_id where u.sex = #{model.sex} and g.name = #{model.className}
</select>
postman接口测试一下,给定参数。然后Send,返回结果如下。

- 传参类型为集合,比如ArrayLis userIds,String [] ids等。
UserMapper.java
//userIds 用户id集合List<UserInfoVo>getUsersByIds(@Param("userIds")List<Integer> userIds) ;
UserMapper.xml
<!--根据用户ids遍历查询-->
<select id="getUsersByIds" resultMap="BaseResultMap">select u.name as name , g.name as className from user u left join grade g on u.id = g.student_idwhere 1=1<if test="userIds.size() !=0">and u.id in<foreach collection="userIds" item="userId" open="(" separator="," close=")" >#{userId}</foreach></if>
</select>
postman测试一下,看看是否查询出指定id("userIds":[1,2,3])所对应的用户信息;

结果也是直接返回。证明接收数组也是没有任何问题。
接着不知道你们有没有 注意到,我在sql上多拼接了这一句:" where 1=1 ",有哪位小伙伴知道这是为何多此一举么?欢迎评论区告诉bug菌。
提示大家一部分,我userIds传了个空进来,查询出了所有数据结果,结果是正常的。

三、拓展:
1、.xml 常用参数说明

一句话总结来说就是:
resultType用于返回已经定义好的domain,pojo或者jdk定义的基本数据类型,返回的属性需要和domain的属性是一样的,否则是绑定不上的;
而 resultMap是指向一个外部的引用resultMap,当表名和列表不一致时使用resultMap做个映射,但在处理返回结果是基本类型的时候是无能为力的;比如我代码里用到的BaseResultMap,其实就是表字段名与对象中属性名做的映射,column属性指定的是sql返回集对于的字段名,而property指定的是你pojo中的属性字段名称。
2、.xml foreach语法解读
如下边这段
<foreach collection="userIds" item="userId" open="(" separator="," close=")" >#{userId}
</foreach>
解读:其实很好理解。foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合。
foreach元素的属性主要有 item,index,collection,open,separator,close。
其中item表示集合中每一个元素进行迭代时的别名,
index指 定一个名字,用于表示在迭代过程中,每次迭代到的位置,
open表示该语句以什么开始,
separator表示在每次进行迭代之间以什么符号作为分隔符,
close表示以什么结束。
collection属性,是必须指定的。可以是list,array数组、map等。
注意:
-
如果传入的是单参数且参数类型是一个List的时候,collection属性值为list
#{item} -
如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array。
<foreach collection="array" index="index" item="item" open="(" separator="," close=")">#{item}
</foreach>
- 如果传入的参数是多个的时候,我们就需要把它们封装成一个Map了,当然单参数也可。
<select id="selectFor" parameterType="java.util.HashMap" resultType="Blog">select * from tb_log where title like "%"#{title}"%" and id in<foreach collection="ids" index="index" item="item" open="(" separator="," close=")">#{item}</foreach></select>
四、附上部分完整源码:
如下我就把持久层跟xml配置给小伙伴完成展示一下,其余用到的model 、vo等就按照自己的习惯啦,真正需要的也可以评论区告诉我,我会为大家一一解答的。
UserMapper.java
@Component
public interface UserMapper extends BaseMapper<UserEntity> {UserEntity getUserById(@Param("userId") String userId);List<UserInfoVo> getUsers(@Param("model")QueryUserInfoModel model); List<UserInfoVo> getUsersByIds(@Param("userIds")List<Integer> userIds) ;
}
UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.example.demo.dao.UserMapper"><!-- 通用查询映射结果 --><resultMap id="BaseResultMap" type="com.example.demo.Vo.UserInfoVo"><result column="name" property="name" /><result column="className" property="className" /></resultMap><!--根据userId查询--><select id="getUserById" resultType="com.example.demo.Entity.UserEntity">select * from user where id = #{userId}</select><!--根据性别和班级名称查询--><select id="getUsers" resultMap="BaseResultMap">select u.name as name,g.name as className from user u left join grade g on u.id = g.student_id where u.sex = #{model.sex} and g.name = #{model.className}</select><!--根据用户ids遍历查询--><select id="getUsersByIds" resultMap="BaseResultMap">select u.name as name , g.name as className from user u left join grade g on u.id = g.student_idwhere 1=1<if test="userIds.size() !=0">and u.id in<foreach collection="userIds" item="userId" open="(" separator="," close=")" >#{userId}</foreach></if></select></mapper>
/*** 用户基本信息实体*/
@TableName("user")
@Data
public class UserEntity implements Serializable {private static final long serialVersionUID = 1L;@TableId(value = "id", type = IdType.AUTO) //表示该id为自增,新增时候不需要手动设置id。private Integer id;@TableField(value = "name")private String name;@TableField(value = "age")private Integer age;@TableField(value = "sex")private String sex;@TableField(value = "address")private String address;@TableField(value = "describes")private String describes;@Overridepublic String toString() {return this.id + " - " + this.name+ " - " +this.getSex();}}
/*** 班级信息实体*/
@TableName("grade")
@Datapublic class GradeEntity {@TableId(value = "id", type = IdType.AUTO) //表示该id为自增,新增时候不需要手动设置id。private Integer id;@TableField(value = "name")private String name;@TableField(value = "student_id")private Integer studentId;@TableField(value = "create_time")private Date createTime;@TableField(value = "update_time")private Date updateTime;
}
/*** 返回用户班级信息*/
public class UserInfoVo {private String name;private String className;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getClassName() {return className;}public void setClassName(String className) {this.className = className;}
}
接口分发层就自己琢磨啦。其实看bug菌postman调用url及请求方式,一看就都明白啦!有些还是得多靠小伙伴们自己从细节摸索,这样比我百分百教大家要理解的更为深刻。
相关文章:
SpringBoot【九】mybatis-plus之自定义sql零基础教学!
一、前言🔥 环境说明:Windows10 Idea2021.3.2 Jdk1.8 SpringBoot 2.3.1.RELEASE mybatis-plus的基本使用,前两期基本讲的差不多,够日常使用,但是有的小伙伴可能就会抱怨了,若是遇到业务逻辑比较复杂的sq…...
C#,人工智能,深度学习,目标检测,OpenCV级联分类器数据集的制作与《层级分类器一键生成器》源代码
一、目标识别技术概述 1、摘要 目标检测是计算机视觉中最基本和最具挑战性的问题之一,它试图从自然图像中的大量预定义类别中定位目标实例。深度学习技术已成为直接从数据中学习特征表示的强大策略,并在通用目标检测领域取得了显著突破。鉴于这一快速发…...
调度系统:Luigi 的主要特性和功能
Luigi 是一个开源的 Python 工作流管理工具,用于构建批处理作业管道,特别适用于数据工程领域。它被设计用来编排任务和处理任务间的依赖关系,支持自动化复杂的 ETL 流程、数据分析、模型训练等任务。 Luigi 的主要特性和功能: 任…...
C# 探险之旅:第二节 - 定义变量与变量赋值
欢迎再次踏上我们的C#学习之旅。今天,我们要聊一个超级重要又好玩的话题——定义变量与变量赋值。想象一下,你正站在一个魔法森林里,手里拿着一本空白的魔法书(其实就是你的代码编辑器),准备记录下各种神奇…...
AUTOSAR:SOME/IP 概念
文章目录 1. 用例与需求1.1 典型用例1.2 对中间件的要求 2. 协议栈示例3. SOME/IP 概念3.1 中间件整体功能与架构3.2 服务组成元素详细解释 4. 服务发现机制深入剖析5. 总结 1. 用例与需求 1.1 典型用例 信息娱乐系统: 后座娱乐系统连接:允许后排乘客连…...
循序渐进kubenetes Service(Cluster ip、Nodeport、Loadbalancer)
文章目录 部署一个web服务Kubernetes Port ForwardKubernetes ServicesClusterIP ServiceNodePort ServiceLoadBalancer Service 部署一个web服务 准备 Kubernetes 集群后,创建一个名为 web 的新 namespace,然后在该 namespace 中部署一个简单的 web 应…...
深入理解 Apache Shiro:安全框架全解析
亲爱的小伙伴们😘,在求知的漫漫旅途中,若你对深度学习的奥秘、JAVA 、PYTHON与SAP 的奇妙世界,亦或是读研论文的撰写攻略有所探寻🧐,那不妨给我一个小小的关注吧🥰。我会精心筹备,在…...
mac 安装CosyVoice (cpu版本)
CosyVoice 介绍 CosyVoice 是阿里研发的一个tts大模型 官方项目地址:https://github.com/FunAudioLLM/CosyVoice.git 下载项目(非官方) git clone --recursive https://github.com/v3ucn/CosyVoice_for_MacOs.git 进入项目 cd CosyVoic…...
币安移除铭文市场的深度解读:背后原因及其对区块链行业的影响
引言: 就在昨天,2024年12月10号,币安宣布将移除铭文市场(Inscriptions Market)。这一消息引发了全球加密货币社区的广泛关注,尤其是在比特币NFT和数字收藏品市场快速发展的背景下。铭文市场自诞生以来迅速…...
深度学习实战野生动物识别
本文采用YOLOv11作为核心算法框架,结合PyQt5构建用户界面,使用Python3进行开发。YOLOv11以其高效的实时检测能力,在多个目标检测任务中展现出卓越性能。本研究针对野生动物数据集进行训练和优化,该数据集包含丰富的野生动物图像样…...
windows安装使用conda
在Windows系统上安装和使用Conda的详细步骤如下: 一、下载Conda安装包 访问Conda的官方网站Anaconda | The Operating System for AI,点击“Downloads”按钮。在下载页面,选择适合您系统的安装包。通常,对于Windows系统…...
手机租赁系统开发全流程解析与实用指南
内容概要 在如今快速发展的科技时代,手机租赁系统已经成为一种新兴的商业模式,非常符合当下市场需求。那么,在开发这样一个系统的时候,首先要从需求分析和市场调研开始。在这一阶段,你需要了解用户需要什么࿰…...
SpringBoot 开发—— YAML文件深度分析
文章目录 一、YAML概述二、数据表示三、YAML 的语法四、YAML 的应用五、YAML 与其他格式的比较1、YAML vs .properties文件可读性和结构数据类型支持扩展性和灵活性使用场景性能和支持2、YAML vs. JSON3、YAML vs. XML六、使用 YAML 的注意事项七、总结YAML 是非常流行的一种配…...
复合机器人整体解决方案
复合机器人是一种集成移动机器人和协作机器人两项功能为一身的新型机器人,更符合人们想象中“脑、眼、手、脚”融合的机器人终极形态。复合机器人的整体解决方案通常涉及多个方面,包括机器人本体、控制系统、感知系统、执行系统以及周边配套设备等。以下…...
【Oracle11g SQL详解】日期和时间函数:SYSDATE、TO_DATE、TO_CHAR 等
日期和时间函数:SYSDATE、TO_DATE、TO_CHAR 等 在 Oracle 数据库中,日期和时间函数用于处理日期和时间数据。它们在记录创建时间、分析时间间隔、格式化输出等场景中非常重要。本文将详细讲解常用的日期和时间函数及其应用。 一、SYSDATE:获…...
VSCode设置字体
参考文章:【面向小白】vscode最佳实践(2)—— 字体设置(fira code更纱黑体),这篇文章末尾给了安装字体的链接。 配置的字体还是很好看的。 ‘Fira Code Retina’, ‘Sarasa Mono Sc’ 需要注意的一个点&am…...
shell编程入门之提取字符并设置rtc时间
awk用法 awk是一款文本处理工具,通常在Unix和Linux操作系统中使用,用于以行为单位对文本进行处理和操作。它可以读取输入文本,对其进行处理,生成报表、统计信息等,并将结果输出到标准输出设备中。 它主要有以下特点&…...
react 不可变数据更新(Immutable Update)合并对象 类似与Java 的BeanUtils.copyProperties
{ ...state, // 保留原有的 state 的其他部分data: { ...state.data, // 保留 state.data 中的其他字段...action.payload // 使用 action.payload 覆盖 state.data 中需要更新的字段} }这段代码是 Redux 中常见的一种状态更…...
Linux GCC基础用法⑦
在 CentOS 7 系统中使用 GCC 与编写 99 乘法表 一、GCC 简介 GCC(GNU Compiler Collection)是一套功能强大的编程语言编译器,在 CentOS 7 系统中广泛用于编译 C、C等多种编程语言的程序。它能够将源代码转换为可执行文件,让计算…...
PyTorch 切片运算 (Slice Operator)
PyTorch 切片运算 {Slice Operator} 1. [:, -1, :]2. [:, [-1], :]References 1. [:, -1, :] https://github.com/karpathy/llama2.c/blob/master/model.py import torchlogits torch.arange(1, 16) print("logits.shape:", logits.shape) print("logits:\n&…...
手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
51c自动驾驶~合集58
我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留,CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制(CCA-Attention),…...
简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...
el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
JavaScript基础-API 和 Web API
在学习JavaScript的过程中,理解API(应用程序接口)和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能,使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...
(一)单例模式
一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...
Vite中定义@软链接
在webpack中可以直接通过符号表示src路径,但是vite中默认不可以。 如何实现: vite中提供了resolve.alias:通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...
springboot 日志类切面,接口成功记录日志,失败不记录
springboot 日志类切面,接口成功记录日志,失败不记录 自定义一个注解方法 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/***…...

