【MyBatis-Plus 核心接口】BaseMapper 和 IService 深度解析

news2025/1/4 19:20:45

在使用 MyBatis-Plus(简称 MP)进行开发时,BaseMapper 和 IService 接口是我们老朋友了,不知道你会不会跟我一样好奇:为什么实现了 BaseMapperIService 接口,我们就能轻松操作数据库?这背后有哪些工作机制?本文将带你一步步探究,并结合 CRUD 操作分类讲解两者的常用方法。希望这篇博客讲解能给你带来一些收获😘


一、BaseMapper 核心功能

BaseMapper 是 MyBatis-Plus 提供的一个基础接口,用于封装最常见的 CRUD 操作。只要你的实体类对应了这个 Mapper 接口,就能使用其提供的方法与数据库交互

核心原理

  • MP 内置 SQL 解析器BaseMapper 的方法背后是 MP 内置的动态 SQL 解析器,它根据泛型参数(实体类)自动生成 SQL 语句。

  • 无需重复编写:常见的增删改查方法已经内置,实现了开发效率的提升。

常用方法分类

BaseMapper 提供的方法可以分为以下几类:

新增操作
  • 插入一条记录,忽略非空字段。
    int insert(T entity)
    
删除操作
  • 根据主键删除
    int deleteById(Serializable id)
    
  • 根据主键批量删除
    int deleteBatchIds(Collection<? extends Serializable> idList)
    
  • 根据字段条件删除
    int deleteByMap(Map<String, Object> columnMap)
    
更新操作
  • 根据主键更新
    int updateById(@Param("et") T entity)
    
  • 根据条件更新
    int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper)
    
查询操作
  • 根据主键查询
    T selectById(Serializable id)
    
  • 根据主键批量查询
    List<T> selectBatchIds(Collection<? extends Serializable> idList)
    
  • 根据 Map 条件查询
    List<T> selectByMap(Map<String, Object> columnMap)
    
  • 根据条件查询列表
    List<T> selectList(@Param("ew") Wrapper<T> queryWrapper)
    
  • 分页查询
    IPage<T> selectPage(IPage<T> page, @Param("ew") Wrapper<T> queryWrapper)
    

【说明】

  • T 是实体类泛型,代表数据库表的映射对象。
  • Serializable id 是实体类的主键类型。
  • Wrapper 是条件构造器,用于动态生成 SQL 条件。
  • IPage 是分页参数接口,结合分页插件实现分页查询。

代码示例

@Mapper
public interface UserMapper extends BaseMapper<User> {
    // 无需手写基本CRUD方法
}
​
// 使用示例
User user = new User();
user.setName("Tom");
user.setAge(25);
userMapper.insert(user);

二、IService 核心功能

IService 是 MyBatis-Plus 提供的业务层接口,主要封装了对 BaseMapper 的进一步抽象,提供一些常用的业务逻辑方法。

核心原理

  • 依赖 Service 层IService 内部调用 BaseMapper 的方法,通过组合的方式封装业务逻辑。

  • 增强业务扩展性:通过继承 IService,可以更容易添加自定义业务逻辑,同时不影响基础 CRUD 功能。


常用 CRUD 方法一览

IService 方法大部分是对 BaseMapper 方法的封装,并增加了一些便利操作:

新增操作
  • 保存一条记录,忽略非空字段。
    boolean save(T entity)
    
  • 批量插入记录,提高插入效率。
    boolean saveBatch(Collection<T> entityList)
    
删除操作
  • 根据主键删除
    boolean removeById(Serializable id)
    
  • 根据 Map 条件删除
    boolean removeByMap(Map<String, Object> columnMap)
    
  • 根据主键批量删除
    boolean removeBatchIds(Collection<? extends Serializable> idList)
    
更新操作
  • 根据主键更新
    boolean updateById(T entity)
    
  • 根据条件更新
    boolean update(T entity, Wrapper<T> updateWrapper)
    
  • 批量更新记录,支持根据主键更新多个实体。
    boolean updateBatchById(Collection<T> entityList)
    
查询操作
  • 根据主键查询单条记录。
    T getById(Serializable id)
    
  • 根据主键批量查询多个主键对应的记录。
    List<T> listByIds(Collection<? extends Serializable> idList)
    
  • 根据 Map 条件查询符合 Map 条件的记录。
    List<T> listByMap(Map<String, Object> columnMap)
    
  • 根据条件查询符合条件构造器的所有记录。
    List<T> list(Wrapper<T> queryWrapper)
    
  • 分页查询,配合分页插件,返回分页结果。
    IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper)
    

使用示例

保存操作示例
User user = new User();
user.setName("Alice");
user.setAge(30);
userService.save(user);
查询操作示例
List<User> users = userService.listByIds(Arrays.asList(1, 2, 3));
users.forEach(System.out::println);
分页查询示例
IPage<User> page = new Page<>(1, 5); // 第1页,每页5条记录
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.gt("age", 18); // 年龄大于18
IPage<User> result = userService.page(page, queryWrapper);
result.getRecords().forEach(System.out::println);

三、操作数据库的工作机制

接下来我们深入讲解一下 MyBatis-Plus 是如何通过代码生成和动态代理机制实现数据库操作的

  1. 代码生成:MP 基于实体类生成 SQL 映射文件,通过 BaseMapperIService 动态生成常用方法的实现。

  2. 动态代理:MP 使用了 MyBatis 提供的 MapperProxy 动态代理机制,当调用 BaseMapper 的方法时,会动态解析 SQL 并执行。


1. 代码生成机制

MyBatis-Plus 的代码生成器并不是简单的“生成代码文件”,它更像一个“动态 SQL 工厂”。通过结合实体类和数据库表的映射关系,它在运行时动态生成 SQL 并执行,具体如下:

核心实现逻辑
  • 实体类与表映射: 实体类通过 @TableName 和字段注解(如 @TableField)指定表和字段的对应关系。没有显式注解时,MP 会根据约定(如类名与表名的驼峰转下划线规则)推导映射。

  • 自动注入 SQL 操作方法: MP 根据 BaseMapper 的泛型实体类,结合数据库元信息(表名、字段名等),生成对应的 CRUD 方法所需的 SQL 模板。例如:

    • selectById 会生成类似如下的 SQL。

      SELECT * FROM user WHERE id = #{id} 
    • insert 会根据实体类的字段生成

       INSERT INTO user (name, age) VALUES (#{name}, #{age})
  • 动态生成的好处

    • 开发者无需手写基础 SQL。

    • 避免手写 SQL 错误,提升效率。

    • 结合条件构造器Wrapper),还能动态生成复杂 SQL。


2. 动态代理机制

MyBatis-Plus 使用 MyBatis 的 MapperProxy 动态代理机制,拦截 Mapper 接口的调用,将方法转化为 SQL 并执行。这是其实现核心数据库操作的基础。

MapperProxy 的核心逻辑

代理对象生成: 每一个 BaseMapper 实现类,实际上是由 MyBatis 动态代理生成的代理对象。在程序运行时,调用 BaseMapper 的方法并不会直接执行,而是由代理类的 invoke 方法处理。

方法调用的拦截与解析

  1. 方法匹配:当调用 BaseMapper 方法时,MapperProxy 会根据方法签名(方法名、参数类型等)找到对应的 MappedStatement

  2. SQL 解析:MP 扩展了 MyBatis 的 MappedStatement,可以根据方法名(如 selectById)和注解信息动态解析成 SQL。

  3. 执行查询:SQL 解析完成后,通过 MyBatis 的 Executor 层(如 SimpleExecutor 或 BatchExecutor)将 SQL 提交到数据库并返回结果。

与 MyBatis 的区别
  • MyBatis:开发者需要手动在 XML 或注解中定义每个 SQL 语句,方法名和 SQL 没有直接关系。

  • MyBatis-Plus:通过方法名和泛型实体类自动生成 SQL,例如 selectByIdinsert 等方法会根据命名约定生成标准的 CRUD SQL,无需额外配置。


3. 从调用到执行的全过程

以下是一个 BaseMapper.selectById 方法的调用到执行的完整流程,帮助更好理解动态代理和代码生成的协同作用:

  1. 调用阶段: 开发者调用 userMapper.selectById(1),此时 userMapper 是 MyBatis 的代理对象。

  2. 方法拦截: 代理对象的 invoke 方法被触发。它根据方法签名找到对应的 MappedStatementselectById 对应的 SQL 模板为:

    SELECT * FROM {tableName} WHERE id = ?
  3. SQL 生成

    • MP 通过 条件构造器Wrapper元数据(实体类中的元信息(字段名、类型、注解等)),将泛型 User 解析为表名 user

    • 将实体类字段(idname 等)解析为表字段(idname 等)。

    • 动态拼接 SQL:

      SELECT * FROM user WHERE id = 1
  4. 执行阶段

    • MyBatis 的 Executor 层负责将拼接好的 SQL 提交给数据库。

    • 数据库返回结果集,MyBatis 的 ResultHandler 负责将结果集映射为实体对象User 实例)。

  5. 返回结果: 最终,selectById 返回的是一个封装了查询结果的 User 对象。


4. 设计优势

MyBatis-Plus 的动态代理和代码生成机制在设计上有以下优势:

  1. 开发效率:通过自动生成 SQL 和动态代理调用,开发者不需要关心基础 SQL 的编写,大幅减少重复工作。

  2. 安全性:动态生成 SQL 时,会自动处理 SQL 注入风险(如参数使用 PreparedStatement 的形式绑定)。

  3. 扩展性:通过 Wrapper 构造器,支持复杂 SQL 动态生成;同时允许开发者自定义方法扩展。

  4. 统一性:提供了一套一致的 CRUD 方法名和调用规范,降低了团队协作成本

四、总结

BaseMapper

  • 封装了最基础的 CRUD 操作,例如 insertselectByIdupdateByIddeleteById 等,直接操作数据库,适合处理简单的增删改查逻辑。

  • 提供了一种零配置的开发体验,让开发者无需编写重复的 SQL 语句。

IService

  • BaseMapper 进行了进一步封装,包含了一些常用的业务逻辑扩展方法,例如批量插入、分页查询等。

  • 通过继承 IService,开发者可以更方便地在 Service 层添加自定义的业务逻辑,同时利用已有的 CRUD 功能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2269976.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

全新免押租赁系统助力商品流通高效安全

内容概要 全新免押租赁系统的推出&#xff0c;可以说是一场商品流通领域的小革命。想象一下&#xff0c;不再为押金烦恼&#xff0c;用户只需通过一个简单的信用评估&#xff0c;就能快速租到所需商品&#xff0c;这种体验简直令人惊喜&#xff01;这个系统利用代扣支付技术&a…

c++领域展开第八幕——类和对象(下篇 初始化列表、类型转换、static成员)超详细!!!!

文章目录 前言一、初始化列表二、类型转换三、static成员总结 前言 上篇博客我们实现了一个简单的日期类&#xff0c;基本的类和对象是清楚了 今天我们再来学习后面的一些类和对象的语法&#xff0c;慢慢的完善所学的东西 fellow me 一、初始化列表 • 之前我们实现构造函数时…

Linux-Ubuntu之RGBLCD显示屏

Linux-Ubuntu之RGBLCD显示屏 一&#xff0c;实现原理二&#xff0c;驱动代码三&#xff0c;总结1.c语言知识 一&#xff0c;实现原理 采用的是4.3寸 800480显示屏&#xff0c;即每行有800个像素点&#xff0c;每列有480个像素点&#xff0c;外接时钟信号&#xff0c;控制刷新频…

JVM 主要组成部分与内存区域

一、JVM 主要组成部分&#xff1a; JVM的主要包含两个组件和两个子系统&#xff0c;分别为&#xff1a; &#xff08;1&#xff09;本地库接口(Native Interface)&#xff1a;与native lib(本地方法库)交互&#xff0c;融合其他编程语言为Java所用&#xff0c;是与其它编程语言…

如何在鸿蒙本地模拟器中使用HDC工具

引言 HDC是指华为设备连接&#xff08;Huawei Device Connector&#xff09;工具。它的作用类似Android开发的ADB工具。在华为鸿蒙&#xff08;HarmonyOS&#xff09;操作系统的开发过程中&#xff0c;HDC工具起到了至关重要的作用。它允许开发者在开发主机&#xff08;如 PC&…

ruoyi 分页 查询超出后还有数据; Mybatis-Plus 分页 超出后还有数据

修改&#xff1a;MybatisPlusConfig 类中 分页合理化修改为&#xff1a;paginationInnerInterceptor.setOverflow(false);

Unity中实现转盘抽奖效果(二)

如果要使转盘停止时转到到指定位置&#xff0c;应该如何做&#xff1f; 实现思路&#xff1a; 也就是在需要停止的分数的区间范围内&#xff0c;随机一个角度值&#xff0c;然后反推需要在哪个角度开始减速&#xff0c;如果转盘的当前角度和需要开始减速的角度有差值&#xf…

苍穹外卖04——Redis初入门 在店铺打烊or营业状态管理功能中的使用

Redis入门 redis简介 它以键值对的形式存储数据在内存中,并且以极高的性能和灵活性而著称,通常用于缓存、消息代理以及持久化数据。 - 基于内存存储,读写性能高- 适合存储热点数据(热点商品、资讯、新闻)- 企业应用广泛Windows版下载地址:https://github.com/microsoft…

深度学习每周学习总结R2(RNN-天气预测)

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客R5中的内容&#xff0c;为了便于自己整理总结起名为R2&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 目录 0. 总结1. RNN介绍a. 什么是 RNN&#xff1f;RNN 的一般应用场景 b. 传统 RNN …

CUDA与Microsoft Visual Studio不兼容问题

简介&#xff1a;在安装一些 python库时&#xff0c;涉及到第三方库&#xff08;特别是需要引用 C 代码&#xff09;时&#xff0c;通常的安装方式会涉及到编译过程&#xff0c;通常称为"源代码安装"&#xff08;source installation&#xff09;&#xff0c;或是 “…

WordPress网站中如何修复504错误

504网关超时错误是非常常见的一种网站错误。这种错误发生在上游服务器未能在规定时间内完成请求的情况下&#xff0c;对访问者而言&#xff0c;出现504错误无疑会对访问体验大打折扣&#xff0c;从而对网站的转化率和收入造成负面影响。 504错误通常源于服务器端或网站本身的问…

Springboot 升级带来的Swagger异常

当升级到Springboot 2.6.0 以上的版本后&#xff0c;Swagger 就不能正常工作了, 启动时报如下错误。当然如果你再使用sping boot Actuator 和 Springfox, 也会引起相关的NPE error. (github issue: https://github.com/springfox/springfox/issues/3462) NFO | jvm 1 | 2022/04…

发现API安全风险,F5随时随地保障应用和API安全

分析数据显示&#xff0c;目前超过90%的基于Web的网络攻击都以API端点为目标&#xff0c;试图利用更新且较少为人所知的漏洞&#xff0c;而这些漏洞通常是由安全团队未主动监控的API所暴露。现代企业需要一种动态防御策略&#xff0c;在风险升级成代价高昂、令人警惕且往往无法…

【数据结构】(Python)差分数组。差分数组与树状数组结合

差分数组&#xff1a; 基于原数组构造的辅助数组。用于区间修改、单点查询。区间修改的时间复杂度O(1)。单点查询的时间复杂度O(n)。差分数组的元素&#xff1a;第一个元素等于原数组第一个元素&#xff0c;从第二个元素开始是原数组对应下标的元素与前一个元素的差&#xff0…

12.30-1-5学习周报

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 文章链接摘要Abstract一、方法介绍1.HAT-CIR2.Horde3.DWGRNet 二、实验总结 文章链接 https://arxiv.org/pdf/2405.04101 摘要 本博客介绍了论文《Continual lea…

Android OpenGl(二) Shader

一、Shader 1、什么是Shader&#xff0c;为什么要使用Shder &#xff08;1&#xff09;shader运行在gpu上的小程序 &#xff08;2&#xff09;以前使用固定管线&#xff0c;但缺点是灵活度不够&#xff0c;无法满足复杂需求&#xff0c;为了解决固定管线的缺点&#xff0c;出…

【LeetCode】200、岛屿数量

【LeetCode】200、岛屿数量 文章目录 一、并查集1.1 并查集1.2 多语言解法 二、洪水填充 DFS2.1 洪水填充 DFS 一、并查集 1.1 并查集 // go var sets int var father [90000]intfunc numIslands(grid [][]byte) int {n, m : len(grid), len(grid[0])build(grid, n, m)for i …

[最佳方法] 如何将视频从 Android 发送到 iPhone

概括 将大视频从 Android 发送到 iPhone 或将批量视频从 iPhone 传输到 Android 并不是一件容易的事情。也许您已经尝试了很多关于如何将视频从 Android 发送到 iPhone 15/14 的方法&#xff0c;但都没有效果。但现在&#xff0c;通过本文中的这 6 种强大方法&#xff0c;您可…

MetaRename for Mac,适用于 Mac 的文件批量重命名工具

在处理大量文件时&#xff0c;为每个文件手动重命名既耗时又容易出错。对于摄影师、设计师、开发人员等需要频繁处理和整理文件的专业人士来说&#xff0c;找到一款能够简化这一过程的工具是至关重要的。MetaRename for Mac 就是这样一款旨在提高工作效率的应用程序&#xff0c…

QEMU网络配置简介

本文简单介绍下qemu虚拟机网络的几种配置方式。 通过QEMU的支持&#xff0c;常见的可以实现以下4种网络形式&#xff1a; 基于网桥&#xff08;bridge&#xff09;的虚拟网络。基于NAT&#xff08;Network Addresss Translation&#xff09;的虚拟网络。QEMU内置的用户模式网…