如何利用 MyBatis 的插件拦截机制在执行 SQL 前自动化实现多租户数据权限隔离

千浩同学_4587

千浩同学_4587

2026-04-23

579人浏览

原创

MyBatis 插件必须拦截 StatementHandler,因其负责 SQL 拼接、参数绑定与执行准备;Executor 拦截太晚,ParameterHandler 不参与 SQL 结构改写。

如何利用 mybatis 的插件拦截机制在执行 sql 前自动化实现多租户数据权限隔离

MyBatis 插件拦截的是哪个处理器?

必须拦截 StatementHandler,而不是 Executor 或 ParameterHandler。因为 SQL 语句的最终拼接、参数绑定和执行准备都在 StatementHandler 阶段完成;Executor 拦截太晚(已生成完整 SQL),ParameterHandler 只管参数,不参与 SQL 结构改写。

常见错误是误用 @Intercepts 注解指向 Executor.update,结果发现 WHERE 条件根本加不进去——SQL 已经解析完毕,再改 BoundSql 无效。

  • 正确目标方法:StatementHandler.prepare 或 StatementHandler.query
  • 需重写 intercept 方法,在调用 invocation.proceed() 前修改 MappedStatement 的 sqlSource
  • 推荐用 BoundSql + SqlSource 替换方式,避免直接字符串拼接引发 SQL 注入或语法错误

如何安全地改写原始 SQL 并注入 tenant_id 条件?

不能简单在 SQL 字符串末尾追加 AND tenant_id = 'xxx'。原始 SQL 可能无 WHERE 子句、可能含子查询、可能带 UNION,硬拼会破坏语法结构,导致 MySQLSyntaxErrorException 或逻辑错误。

正确做法是用 SQL 解析器(如 JSqlParser)解析 AST,定位到主查询的 WHERE 节点,再插入条件表达式。MyBatis-Plus 内部正是这么做的。

  • 若自己实现:优先使用 JSqlParser 解析 SELECT/UPDATE/DELETE 语句,调用 PlainSelect.getWhere() 获取并合并条件
  • 注意处理 INSERT 场景:插件不负责自动填充字段值,那是 MetaObjectHandler 的事;拦截器只管“查/改/删”时的过滤
  • 忽略表判断必须在解析前做,比如 sys_user 是系统表,不应加租户条件,否则管理员登录都失败

tenant_id 从哪来?ThreadLocal 是唯一可靠方式吗?

是的,ThreadLocal 是当前线程内最直接、最可控的传递方式。JWT Filter、LoginController 或网关层解析租户标识后,必须存入 TenantContext.getTenantId() 这类静态方法封装的 ThreadLocal 中。

别用 Spring 的 RequestContextHolder ——它依赖 Servlet 容器,在异步线程(如 @Async、定时任务、MQ 消费)中会丢失上下文,导致 tenant_id 为空或错乱,数据隔离失效。

  • 务必在异步场景手动透传:比如用 TaskDecorator 包装线程池,或在 RabbitListener 中显式调用 TenantContext.setTenantId(...)
  • 不要从数据库查租户 ID 再塞进 ThreadLocal:那意味着每次请求都要多一次 DB 查询,违背“零侵入”初衷
  • 测试时容易漏掉:单元测试未初始化 TenantContext,导致所有 SQL 都没加条件,测试通过但线上出事

为什么 TenantLineInnerInterceptor 比手写插件更稳?

因为 TenantLineInnerInterceptor 已内置对复杂 SQL 的兼容逻辑:支持 JOIN 表、子查询、UNION ALL、LIMIT、GROUP BY 等场景,并自动跳过 INSERT INTO ... SELECT 这类嵌套查询中的子句。

手写插件若只处理最简 SELECT * FROM t,上线后遇到 SELECT u.name, d.dept_name FROM user u JOIN dept d ON u.dept_id = d.id 就会挂掉——解析失败或条件加错位置。

  • 除非有特殊需求(如多租户 + 部门级双维度过滤),否则直接用 TenantLineInnerInterceptor + 自定义 TenantLineHandler
  • 注意版本:3.5.3+ 才支持 INSERT 场景的自动填充(需配合 MetaObjectHandler)
  • 配置顺序很重要:TenantLineInnerInterceptor 必须在 PaginationInnerInterceptor 之前注册,否则分页 SQL 被先改写,租户条件可能被吞掉

真正难的不是加一行 AND tenant_id = ?,而是确保它出现在每一个该出现的地方、且只出现在该出现的地方——包括嵌套查询、批量更新、甚至 MyBatis 的缓存 key 计算里。稍有疏忽,租户数据就裸奔。

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
mybatis一级缓存和二级缓存
mybatis一级缓存和二级缓存

在MyBatis中,一级缓存和二级缓存是两种不同级别的缓存机制,它们都可以用来提高性能。本专题提供mybatis一级缓存和二级缓存相关文章,大家可以免费阅读。

2023.08.21

583

4

ibatis和mybatis有什么区别
ibatis和mybatis有什么区别

ibatis和mybatis的区别:1、基本信息不同;2、开发时间不同;3、功能与易用性;4、配置文件;5、入参类型与出参类型;6、返回结果集接受方式;7、语法差异;8、数据库方言支持;9、插件支持;10、社区活跃度;11、全球化支持。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.02.23

2922

5

mybatis如何配置数据库连接
mybatis如何配置数据库连接

mybatis配置数据库连接的方法:1、指定数据源;2、配置事务管理器;3、配置类型处理器和映射器;4、使用环境元素;5、配置别名。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.02.23

446

5

mybatis工作原理及流程是什么
mybatis工作原理及流程是什么

mybatis工作原理及流程:1、配置文件;2、接口与映射;3、sql解析与生成;4、执行计划;5、结果处理;6、动态sql;7、缓存机制;8、插件;9、事务管理;10、日志与监控;11、扩展性。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.02.23

292

4

hibernate和mybatis有哪些区别
hibernate和mybatis有哪些区别

hibernate和mybatis的区别:1、实现方式;2、性能;3、对象管理的对比;4、缓存机制。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.02.23

302

5

Java MyBatis框架
Java MyBatis框架

本专题专注于Java主流ORM框架MyBatis的应用,系统讲解SQL映射、动态SQL、结果映射、分页查询、缓存机制与多表关联等核心内容,并结合企业管理系统、电商平台和后台管理项目实战,帮助学员全面掌握高效的数据库持久层开发技能。

2025.08.26

6309

22

DBeaver怎么导入数据
DBeaver怎么导入数据

DBeaver数据导入专题,整理Excel、CSV、SQL、TXT等常见文件的数据导入方法,涵盖目标数据库选择、数据表创建、字段映射、数据类型设置及导入参数配置等操作,帮助用户将本地文件中的数据写入数据库,并了解批量导入、重复数据处理和导入失败等常见问题的解决方法。

2026.11.05

0

12

DBeaver安全防护教程大全
DBeaver安全防护教程大全

DBeaver安全防护专题,围绕数据库连接安全、账号密码保护和访问权限管理展开,整理SSL/TLS加密连接、SSH隧道、数据库凭据保存及证书验证等配置方法,同时介绍敏感信息保护、远程连接风险和高权限账号使用等注意事项,帮助用户提高数据库日常管理的安全性。

2026.11.05

0

12

DBeaver连接创建与配置教程
DBeaver连接创建与配置教程

本专题聚焦DBeaver数据库连接配置与管理,覆盖从新建连接、选择数据库类型到填写连接参数和验证连接的完整流程。针对MySQL、PostgreSQL、SQL Server等常见数据库,整理相应的连接设置方法,并提供驱动缺失、认证失败和连接异常等问题的排查方向。

2026.11.04

0

16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.7万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 134.1万人学习