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&…...
从零到一:深度解析BertTokenizer.from_pretrained的加载机制与实战技巧
1. 初识BertTokenizer.from_pretrained:你的NLP敲门砖 第一次接触Hugging Face的Transformers库时,我被BertTokenizer.from_pretrained()这个方法深深吸引了。它就像是一把万能钥匙,能快速打开各种预训练语言模型的大门。记得当时我尝试用传统…...
腾讯混元翻译模型HY-MT1.5-1.8B:免费开源,企业级翻译解决方案
腾讯混元翻译模型HY-MT1.5-1.8B:免费开源,企业级翻译解决方案 1. 引言 1.1 为什么选择HY-MT1.5-1.8B 在全球化的商业环境中,语言障碍成为企业拓展国际市场的首要挑战。腾讯混元团队推出的HY-MT1.5-1.8B翻译模型,以其18亿参数的…...
Ostrakon-VL终端实战:从扫码识别到生成抖音短视频脚本的创意延伸
Ostrakon-VL终端实战:从扫码识别到生成抖音短视频脚本的创意延伸 1. 像素特工终端介绍 想象你是一名零售侦探,手持的不是笨重的扫描枪,而是一个充满复古游戏风格的AI终端。这就是基于Ostrakon-VL-8B模型开发的像素风格交互界面,…...
无噪音RS1 ROSAHL 电解式除湿器 3D 打印耗材盒/户外摄像头/激光器精准除湿设备
RS1 是 ROSAHL(日本 Ryosai Technica 生产)推出的一款超紧凑型电解式除湿器,采用全球领先的固体聚合物电解质(SPE)膜技术,通过电化学原理主动将密闭空间内的水分子分解并以气态形式排出。它具备无噪音、无振…...
Vue3前端集成Gemma-3-12B-IT:构建智能聊天界面
Vue3前端集成Gemma-3-12B-IT:构建智能聊天界面 用最简单的方式,让你的Vue3项目拥有智能对话能力 1. 为什么要在Vue3中集成智能聊天功能 现在很多网站和应用都需要智能对话功能,不管是客服系统、学习助手还是内容创作工具。Gemma-3-12B-IT作为…...
Java应用Istio mTLS启用后gRPC调用持续超时?紧急解锁x509证书链校验、SNI配置与Java SSLContext动态刷新机制
第一章:Java应用Istio mTLS启用后gRPC调用持续超时?紧急解锁x509证书链校验、SNI配置与Java SSLContext动态刷新机制当Istio启用严格mTLS(STRICT模式)后,Java客户端通过gRPC调用服务端频繁出现DEADLINE_EXCEEDED超时&a…...
别再死记硬背DAQmx流程了!LabVIEW数据采集核心逻辑拆解:以USB-6008正弦波实验为例
从设计模式视角重构LabVIEW数据采集:以USB-6008正弦波实验为例 当LabVIEW新手第一次接触DAQmx数据采集时,往往会被"创建任务→添加通道→配置时钟→开始任务→读取数据→清除任务"的固定流程所困扰。这种机械记忆不仅容易遗忘,更难…...
掌握MEAN.JS模块化开发:5个核心模块实战指南与最佳实践
掌握MEAN.JS模块化开发:5个核心模块实战指南与最佳实践 【免费下载链接】mean MEAN.JS - Full-Stack JavaScript Using MongoDB, Express, AngularJS, and Node.js - 项目地址: https://gitcode.com/gh_mirrors/mea/mean MEAN.JS作为基于MongoDB、Express、…...
XUnity.AutoTranslator:如何为Unity游戏构建高效的多语言本地化系统
XUnity.AutoTranslator:如何为Unity游戏构建高效的多语言本地化系统 【免费下载链接】XUnity.AutoTranslator 项目地址: https://gitcode.com/gh_mirrors/xu/XUnity.AutoTranslator XUnity.AutoTranslator是一个专为Unity游戏设计的自动翻译插件,…...
第三章、CLion+GCC+OpenOCD构建STM32标准库开发环境:从零到调试的完整实践
1. 环境准备与工具链安装 搭建STM32标准库开发环境的第一步,就是准备好所有必要的工具。这里我们需要三个核心组件:CLion作为集成开发环境、arm-none-eabi-gcc作为编译器、OpenOCD作为调试器。这三个工具的组合,可以让我们在Windows平台上获得…...

