一、service接口提供的方法

1-1、removebyids和removebatchbyids
核心区别:sql 执行方式:
| 方法 | 生成的 sql | 执行次数 | 性能特点 |
|---|---|---|---|
| removebyids | delete from table where id in (?, ?, ?) | 1 次 sql | 快,适合中小批量(< 1000) |
| removebatchbyids | 多条 delete from table where id = ? | n 次 sql(每个 id 一条) | 慢,但可绕过 in 子句限制 |
示例:假设 id 列表为 [1, 2, 3]:
removebyids(arrays.aslist(1,2,3))
delete from user where id in (1, 2, 3);
一次执行,高效。
removebatchbyids(arrays.aslist(1,2,3))
delete from user where id = 1; delete from user where id = 2; delete from user where id = 3;
三次独立 sql,效率低。
1、为什么要有removebatchbyids?——解决in的限制
虽然 removebyids 更高效,但在某些数据库或场景下存在限制:
- mysql:in 列表长度理论上可达数万,但过长会影响性能或触发 max_allowed_packet 限制。
- oracle:in 子句最多支持 1000 个元素(硬限制!超过会报错)。
- sql server / db2:也有类似限制。
此时,如果你要删 1500 条 oracle 记录:
- removebyids(list) → ❌ 报错:ora-01795: maximum number of expressions in a list is 1000
- removebatchbyids(list) → ✅ 虽慢但能跑通(逐条删)
💡 实际上,mp 的 removebatchbyids 内部还会做分批次提交(默认每 1000 条一批),避免事务过大。
2、补充:removebatchbyids的“批”不是 jdbc batch!
注意:虽然叫 “batch”,但它不是 jdbc 的批处理(addbatch/executebatch),而是指“分批循环执行单条 delete”。
如果想用真正的 jdbc batch 提升性能,mp 目前不直接支持(需自定义 sql 或用 sqlrunner)。
3、小结
| 场景 | 推荐方法 |
|---|---|
| 一般批量删除(id 数 < 500) | ✅ removebyids(高效) |
| oracle 删除 >1000 条 | ✅ removebatchbyids(绕过 in 限制) |
| 需要事务控制 + 大量删除 | ⚠️ 考虑分页删除 + removebyids(如每次删 500 条) |
| 追求极致性能(万级删除) | 🔧 自定义 sql + foreach 或物理分区删除 |
1-2、service接口的实现

- 自定义接口需要extends iservice接口;
- 自定义实现类,需要extends serviceimpl实现类;
【对比】:
mapper接口,没有实现类;因为mybatis 通过 jdk 动态代理(dynamic proxy)在运行时自动生成了 mapper 接口的实现类
1-3、mybatis 动态代理,详细原理分解
1.mybatis 的核心机制:mapperproxy
当你调用 usermapper.selectbyid(1) 时,实际上执行的是 mybatis 内部生成的一个 代理对象(proxy)。
- mybatis 在启动时(spring 容器初始化阶段),会扫描所有被 @mapper 注解标记的接口,或通过 @mapperscan 扫描的包。
- 对每个 mapper 接口,mybatis 使用 jdk 动态代理 创建一个实现了该接口的代理类。
- 这个代理类的逻辑由 mapperproxy 类统一处理。
📌 关键类:org.apache.ibatis.binding.mapperproxy
2.代理做了什么?
当调用 usermapper.selectbyid(1) 时,流程如下:
- 调用被代理对象的方法 → 触发 mapperproxy.invoke()
- mapperproxy 根据 方法名 + 参数类型,去 mybatis 的 mappedstatement 注册表中查找对应的 sql 语句
- 对于 mp 的 basemapper 方法(如 selectbyid),mp 已经在启动时自动注册了通用 sql。
- 对于自定义方法(如 selectbyname),mybatis 会从 xml 或 @select 注解中解析 sql。
- 执行 sql,封装结果,返回。
3.mybatis-plus 的增强
mp 在 mybatis 基础上进一步自动化:
- basemapper<t> 中的 crud 方法(如 insert, deletebyid, selectlist 等)无需你写 sql。
- mp 在应用启动时,通过 反射 + 泛型分析,自动为每个实体生成对应的通用 sql(比如根据表名、字段名拼装)。
- 这些 sql 被注册到 mybatis 的 configuration 中,供 mapperproxy 调用。
💡 本质:mp 把“模板化 sql” 自动生成并注册,而 mybatis 负责代理调用。
4.spring 是如何管理这个代理 bean 的?
- 当你使用 @mapperscan("com.example.mapper") 时,mybatis-spring 提供了一个 mapperscannerconfigurer。
- 它会把指定包下的所有接口,注册为 spring bean,bean 的实例就是 mybatis 生成的代理对象。
- 所以你可以用 @autowired 正常注入。
最终:usermapper 在 spring 容器中是一个 由 mybatis 生成的代理对象,不是 null,也不是你写的类。
5、验证:打印 mapper 实例的类名
system.out.println(usermapper.getclass().getname());
输出可能是:com.sun.proxy.$proxy89
6、总结一句话:
mybatis-plus(基于 mybatis)在运行时通过 jdk 动态代理,为 mapper 接口自动生成了代理实现类,无需开发者手动编写。
补充说明:
- 这个“代理实现类”不是 mp 单独做的,而是 mybatis 的核心机制,mp 是在此基础上增强了 crud 能力。
- 所以准确说是:mybatis 负责生成代理,mp 负责填充通用 sql 逻辑。
1-4、service接口-小结

二、controller中使用@autowired注入service接口而非实现类
在spring mvc的controller中使用@autowired注入service接口而非实现类,主要有以下几个原因:
1.面向接口编程
这是面向对象设计的核心原则之一。依赖接口而非具体实现,可以降低代码耦合度,提高系统的可维护性和可扩展性。
2.依赖倒置原则(dip)
高层模块(controller)不应该依赖低层模块(serviceimpl),两者都应该依赖抽象(service接口)。这样可以让代码更加灵活,易于修改。
3.便于切换实现
如果业务需求变化,需要更换service的实现方式,只需要:
- 创建新的实现类
- 修改配置或使用
@primary、@qualifier指定实现 - controller代码无需修改
// controller中的代码始终不变
@autowired
private userservice userservice;
// 可以轻松切换实现
@service
public class userserviceimpl implements userservice { }
@service
@primary // 优先使用这个实现
public class userserviceimplv2 implements userservice { }
4.便于单元测试
测试时可以轻松mock接口,而不需要依赖具体实现:
@springboottest
class usercontrollertest {
@mockbean
private userservice userservice; // 轻松mock接口
@autowired
private usercontroller controller;
}
5.支持aop和代理
spring的很多功能(如事务管理、缓存)是通过动态代理实现的。注入接口可以让spring更灵活地创建代理对象。
6.符合开闭原则
对扩展开放,对修改关闭。新增功能时只需增加新的实现类,而不修改现有代码。
注意: 即使注入的是接口,spring在运行时注入的仍然是实现类的实例(或其代理对象),只是通过接口类型来引用它。
到此这篇关于mybatisplus中iservice接口基本用法的文章就介绍到这了,更多相关mybatisplus iservice接口用法内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论