MyBatis-Plus——SQL注入器

MyBatis-Plus的SQL注入器其实是一种“扩展工具包”机制——当BaseMapper提供的默认方法(如selectById、deleteById)不够用时,我们可以通过它自定义通用方法,让所有Mapper接口都能直接使用。这里提供一个案例:自定义一个“删除表中所有数据”的deleteAll方法,用“工具箱”的比喻一步步拆解。

一、先理解核心需求:为什么需要自定义deleteAll?

MyBatis-Plus的BaseMapper虽然提供了很多基础方法,但没有“删除全表数据”的deleteAll方法(可能是为了安全,避免误操作)。如果多个表都需要“删除全表”功能,总不能在每个Mapper里重复写SQL吧?

这时候就需要SQL注入器:把deleteAll定义成“全局通用方法”,让所有继承BaseMapper的接口(比如StudentMapper、UserMapper)都能直接调用,不用重复开发。

二、逐步拆解:每个类的作用

1. 自定义方法类(DeleteAll):定义“具体工具”

// 注入方法类:相当于定义一个"删除全表"的工具
public class DeleteAll extends AbstractMethod {
  @Override
  public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
    // 1. 定义要执行的SQL:delete from 表名(表名通过tableInfo获取,自动适配不同表)
    String sql = "delete from " + tableInfo.getTableName();
    
    // 2. 定义方法名:和Mapper接口中声明的方法名一致(这里是deleteAll)
    String method = "deleteAll";
    
    // 3. 构建SqlSource:MyBatis中用于传递SQL的对象
    SqlSource sqlSource = this.languageDriver.createSqlSource(this.configuration, sql, modelClass);
    
    // 4. 构建删除类型的MappedStatement(MyBatis执行SQL的核心对象)
    return this.addDeleteMappedStatement(mapperClass, method, sqlSource);
  }
}

作用:这是“具体工具的设计图”,定义了deleteAll方法要执行的SQL(删除全表)、方法名,以及如何生成MyBatis能识别的执行对象(MappedStatement)。

继承AbstractMethod的原因:MyBatis-Plus通过AbstractMethod统一管理方法生成逻辑,我们只需按照它的规范实现即可。

2. SQL注入器(MySqlInject):将“工具”放入“公共工具箱”

// SQL自动注入器:相当于把自定义工具放到所有Mapper都能访问的公共工具箱
@Component
public class MySqlInject extends AbstractSqlInjector {
  @Override
  public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
    List<AbstractMethod> methods = new ArrayList<>();
    // 把自定义的DeleteAll方法添加到方法列表中
    methods.add(new DeleteAll()); 
    return methods;
  }
}

作用:注入器的职责是“收集所有自定义方法”,并在MyBatis-Plus启动时,将这些方法注入到所有继承BaseMapper的接口中。

简单说:没有注入器,DeleteAll方法只是一个孤立的类;有了注入器,它会告诉MyBatis-Plus:“把deleteAll方法加到所有Mapper里,让它们都能用”。

3. 在Mapper接口中声明方法:“告诉工具箱要用这个工具”

// StudentMapper:具体的工具箱,继承BaseMapper后,自动获得基础工具+注入的自定义工具
public interface StudentMapper extends BaseMapper<Student> {
  // 声明deleteAll方法(无需实现,因为注入器已经帮我们生成了实现)
  void deleteAll();
}

为什么只声明不实现?
因为DeleteAll类已经通过注入器生成了对应的SQL和执行逻辑,这里只是“告诉MyBatis:我要用这个方法”,实际执行时会找到注入器生成的实现。

4. 注销BlockAttackInnerInterceptor插件:“暂时关闭安全锁”

@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
  MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
  interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
  // 注释掉防全表删除插件:因为deleteAll就是全表删除,会被它拦截
  // interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor()); 
  interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
  return interceptor;
}

原因:BlockAttackInnerInterceptor是MyBatis-Plus的“安全插件”,会拦截全表删除/更新(防止误操作)。而我们的deleteAll就是要全表删除,所以需要暂时注释掉,否则会执行失败。

5. 测试方法:“使用工具”

@Test
public void testDeleteAll() {
  // 直接调用StudentMapper中的deleteAll方法
  studentMapper.deleteAll();
}

此时调用的deleteAll,就是我们通过注入器自定义的全表删除方法。

三、完整执行流程:从启动到调用

用“工具箱准备→使用工具”的流程理解:

  1. 启动阶段:准备工具箱

    • 项目启动时,Spring会加载MySqlInject(因为加了@Component);
    • MySqlInject的getMethodList方法被调用,返回包含DeleteAll的方法列表;
    • MyBatis-Plus会根据这些方法,为所有继承BaseMapper的接口(如StudentMapper)生成对应的实现逻辑(即MappedStatement,包含SQL和执行方式);
    • 最终,StudentMapper不仅有BaseMapper的默认方法,还多了deleteAll方法。
  2. 调用阶段:使用工具

    • 执行studentMapper.deleteAll()时,MyBatis会找到注入器生成的MappedStatement;
    • 执行其中定义的SQL:delete from student(表名由TableInfo自动获取,对应Student实体类的表);
    • 数据库执行全表删除,完成操作。

四、总结

SQL注入器就像“全局工具注册中心”:

  • 自定义方法类(DeleteAll)是“工具的设计图”,定义了工具的功能(执行什么SQL);
  • 注入器(MySqlInject)是“工具管理员”,把工具分发到所有Mapper的“工具箱”里;
  • Mapper接口声明方法是“告诉管理员要用这个工具”;
  • 最终,我们可以在任何Mapper中直接使用这个工具(调用方法)。

这种机制的好处是:一次定义,到处使用,避免重复开发通用方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值