一、核心概念

什么是 BlockAttackInnerInterceptor

BlockAttackInnerInterceptor 是 MyBatis-Plus 内置的一个SQL 执行分析拦截器,用于在执行 SQL 前进行语义分析,主动阻断可能造成全表更新或全表删除的危险操作

核心功能

  • 防止 UPDATEWHERE 条件 → 避免全表更新
  • 防止 DELETEWHERE 条件 → 避免全表删除
  • 防止 UPDATE / DELETE 仅含 WHERE 1=1 或恒真条件 → 防止恶意或错误 SQL
  • 不检查 SELECT(如 SELECT * FROM table 不会阻断)

工作原理

  1. 在 SQL 执行前,MyBatis-Plus 通过 MybatisPlusInterceptor 拦截 UPDATEDELETE 语句。
  2. 解析 SQL 的 WHERE 条件部分。
  3. 判断是否满足“无有效 WHERE 条件”:
    • WHERE 子句
    • WHERE 子句为 1=1trueid IS NOT NULL 等恒真表达式
  4. 若判断为“全表操作”,则抛出异常,阻断执行

🔍 底层技术:基于 JSQLParser 或 MyBatis-Plus 自研 SQL 解析器进行 AST(抽象语法树)分析。


二、操作步骤(超详细)

第一步:添加依赖(确保版本 ≥ 3.4.0)

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.6</version>
</dependency>

⚠️ BlockAttackInnerInterceptorMyBatis-Plus 3.4.0 开始引入,旧版本使用已废弃的 SqlExplainInterceptor


第二步:配置 MybatisPlusInterceptor 并注册插件

创建配置类 MyBatisPlusConfig.java

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * MyBatis-Plus 配置类
 */
@Configuration
public class MyBatisPlusConfig {

    /**
     * 配置 MyBatis-Plus 拦截器链
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();

        // 添加 SQL 阻断攻击插件(必须放在前面)
        interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());

        // 可同时添加其他插件(顺序重要)
        // interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); // 乐观锁
        // interceptor.addInnerInterceptor(new PaginationInnerInterceptor());       // 分页

        return interceptor;
    }
}

关键点

  • 必须通过 MybatisPlusInterceptor 注册
  • BlockAttackInnerInterceptor 应尽早添加(建议第一个)

第三步:编写测试代码验证阻断功能

场景 1:全表删除(应被阻断)

@Service
@RequiredArgsConstructor
public class UserService {

    private final UserMapper userMapper;

    /**
     * 测试全表删除 → 应被 BlockAttackInnerInterceptor 阻断
     */
    public void deleteAll() {
        // ❌ 危险操作!无 WHERE 条件
        userMapper.delete(null); // 或 new QueryWrapper<>()
    }
}

执行结果

org.mybatis.spring.MyBatisSystemException: 
nested exception is com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: 
prohibition of full table deletion

场景 2:全表更新(应被阻断)

public void updateAll() {
    UserDO user = new UserDO();
    user.setAge(99);
    // ❌ 危险操作!无 WHERE 条件
    userMapper.update(user, null); // 或 new UpdateWrapper<>()
}

执行结果

MybatisPlusException: prohibition of full table operation

场景 3:正常删除(应通过)

public void deleteUserById(Long id) {
    // ✅ 正常操作,有明确 WHERE 条件
    userMapper.deleteById(id);
}

执行结果:成功执行,无异常。


场景 4:带条件的更新(应通过)

public void updateUserByName(String name, Integer newAge) {
    UserDO user = new UserDO();
    user.setAge(newAge);
    userMapper.update(user, new UpdateWrapper<UserDO>().eq("name", name));
}

执行结果:成功执行。


第四步:测试 WHERE 1=1 等恒真条件

public void updateWithTrueCondition() {
    UserDO user = new UserDO();
    user.setAge(100);
    // ❌ 虽有 WHERE,但为恒真条件,仍被视为全表操作
    userMapper.update(user, new UpdateWrapper<UserDO>().apply("1=1"));
}

执行结果:被阻断,抛出异常。


三、常见错误与解决方案

错误现象 原因 解决方案
插件不生效 未正确注册 BlockAttackInnerInterceptor 检查配置类是否加载,插件是否添加
DELETE 被阻断但 UPDATE 不是 插件顺序问题 确保 BlockAttackInnerInterceptor 在链中
updateById 被阻断 传入的 idnull 检查 id 是否为空
启动报错 ClassNotFoundException 版本过低 升级到 MP 3.4.0+
QueryWrapper 使用不当导致误杀 .apply("status = status") 避免使用恒真表达式
批量操作被阻断 updateBatchById 内部可能触发 检查批量更新的 id 是否为空

四、注意事项

  1. 仅拦截 UPDATEDELETE:对 INSERTSELECT 无影响。
  2. 不支持 QueryWrapper.or() 复杂逻辑:过于复杂的 WHERE 可能误判,建议避免。
  3. 与逻辑删除共存:如果使用 @TableLogicDELETE 操作会转为 UPDATE,仍受阻断规则影响。
  4. 测试环境可关闭:开发/测试环境可选择性关闭,生产环境必须开启
  5. 异常类型:抛出 MybatisPlusException,建议全局异常处理器捕获并返回友好提示。
  6. 性能影响极小:SQL 解析开销可忽略,适用于高并发场景。

五、使用技巧

1. 开发环境动态关闭插件

@Bean
@Profile({"prod"}) // 仅在生产环境启用
public MybatisPlusInterceptor mybatisPlusInterceptor() {
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    if ("prod".equals(environment.getActiveProfiles()[0])) {
        interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
    }
    return interceptor;
}

2. 自定义阻断逻辑(高级)

虽然 BlockAttackInnerInterceptor 不支持直接扩展,但可通过自定义 InnerInterceptor 实现:

@Component
public class CustomBlockInterceptor implements InnerInterceptor {

    @Override
    public void beforePrepare(StatementHandler sh, Statement stmt, int transactionTimeout) {
        BoundSql boundSql = sh.getBoundSql();
        String sql = boundSql.getSql().toLowerCase();

        // 简单判断(不推荐,建议用 AST 解析)
        if ((sql.contains("update") || sql.contains("delete")) 
            && !sql.contains("where")) {
            throw new RuntimeException("禁止执行无 WHERE 条件的 UPDATE/DELETE");
        }
    }
}

⚠️ 建议:优先使用官方 BlockAttackInnerInterceptor,更稳定。

3. 结合日志监控

// 在全局异常处理器中记录
@ExceptionHandler(MybatisPlusException.class)
public ResponseEntity<?> handleMybatisPlusException(MybatisPlusException e) {
    log.warn("SQL 阻断触发: {}", e.getMessage(), e);
    return ResponseEntity.status(400).body("非法操作已被拦截");
}

六、最佳实践与性能优化

✅ 最佳实践

实践 说明
生产环境强制开启 防止人为或程序错误导致数据灾难
结合代码审查 避免在代码中写 wrapper.apply("1=1")
团队培训 让开发人员了解该插件的存在和作用
异常友好提示 返回“操作非法”而非技术异常
@TableLogic 配合 逻辑删除也应防止全表操作
定期审计日志 查看是否有频繁阻断,排查潜在风险

⚡ 性能优化建议

  • 无性能瓶颈:解析 SQL 的 AST 成本极低,不影响吞吐量。
  • 避免频繁调用:减少不必要的 update(null) 调用。
  • 缓存预编译 SQL:MyBatis 本身已优化,无需额外处理。

七、原理深入:SQL 解析过程(简化版)

BlockAttackInnerInterceptor 内部大致流程:

void beforePrepare(StatementHandler sh, ...) {
    String sql = sh.getBoundSql().getSql();
    
    // 1. 使用 SQL 解析器(如 JSQLParser)解析 SQL
    Statement stmt = CCJSqlParserUtil.parse(sql);
    
    if (stmt instanceof Update || stmt instanceof Delete) {
        Expression where = getWhere(stmt);
        
        // 2. 判断 WHERE 是否为空或恒真
        if (where == null || isAlwaysTrue(where)) {
            throw new MybatisPlusException("prohibition of full table operation");
        }
    }
}

boolean isAlwaysTrue(Expression expr) {
    return expr.toString().matches("(?i)(1=1|true|\\w+ IS NOT NULL)");
}

🔍 实际实现更复杂,会解析 AST 节点判断逻辑恒真性。


总结

BlockAttackInnerInterceptor 是 MyBatis-Plus 提供的数据库安全守护者,通过静态分析 SQL 语义,有效防止全表更新/删除等灾难性操作。

🚀 三步启用

  1. 升级 MP 到 3.4.0+
  2. 配置 MybatisPlusInterceptor 并添加 BlockAttackInnerInterceptor
  3. 生产环境强制开启,开发环境可选

掌握该插件,让你的系统在面对“手滑”或“恶意 SQL”时多一层坚实防护。适用于所有涉及数据修改的业务场景,尤其是金融、电商、后台管理系统等对数据一致性要求高的系统。