news 2026/5/1 7:55:04

如何添加“默认给Sql查询语句加上租户条件”的功能

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
如何添加“默认给Sql查询语句加上租户条件”的功能

从零实现“默认给 SQL 查询语句加上租户条件”的功能,本质上是利用MyBatis Plus的插件机制配合ThreadLocal上下文来实现的。

我们需要构建一条完整的“数据 -> 规则 -> 执行”的链路。以下是标准化的5 步实现指南


第一步:准备“背包” (定义上下文容器)

你需要一个地方在当前线程中存储“当前租户是谁”。

代码核心:利用ThreadLocal

publicclassTenantContextHolder{// 存放当前租户IDprivatestaticfinalThreadLocal<Long>TENANT_ID=newTransmittableThreadLocal<>();publicstaticvoidsetTenantId(LongtenantId){TENANT_ID.set(tenantId);}publicstaticLonggetTenantId(){returnTENANT_ID.get();}publicstaticvoidclear(){TENANT_ID.remove();}}

第二步:制定“规则” (实现 Handler 接口)

你需要告诉 MyBatis Plus 具体的过滤逻辑:租户ID是多少?列名叫什么?哪些表不需要加?

代码核心:实现TenantLineHandler接口。

@ComponentpublicclassMyTenantLineHandlerimplementsTenantLineHandler{// 1. 告诉 MP,当前租户ID是多少 (从背包里拿)@OverridepublicExpressiongetTenantId(){LongtenantId=TenantContextHolder.getTenantId();// 如果没拿到ID(比如没登录),返回 NullValue 可能会导致报错或查不到数据// 通常这里会做判空或者返回默认值returnnewLongValue(tenantId);}// 2. 告诉 MP,数据库里租户列的名字叫什么@OverridepublicStringgetTenantIdColumn(){return"tenant_id";}// 3. 告诉 MP,哪些表需要忽略 (白名单)@OverridepublicbooleanignoreTable(StringtableName){// A. 全局白名单:系统表(字典、菜单)不需要隔离if("sys_dict".equals(tableName)||"sys_menu".equals(tableName)){returntrue;}// B. 动态白名单:配合 @TenantIgnore 注解使用if(TenantContextHolder.isIgnore()){returntrue;}// 默认:必须加过滤条件returnfalse;}}

第三步:组装“引擎” (配置 MyBatis 拦截器)

有了规则(Handler),你需要把它交给执行者(Interceptor),并把执行者放入 MyBatis 的插件链中。

代码核心:配置MybatisPlusInterceptorBean。

@ConfigurationpublicclassMybatisConfig{@BeanpublicMybatisPlusInterceptormybatisPlusInterceptor(MyTenantLineHandlertenantLineHandler){MybatisPlusInterceptorinterceptor=newMybatisPlusInterceptor();// 核心动作:创建租户拦截器,并注入上面的规则 Handler// ⚠️注意:建议放在分页插件之前interceptor.addInnerInterceptor(newTenantLineInnerInterceptor(tenantLineHandler));// 添加分页插件interceptor.addInnerInterceptor(newPaginationInnerInterceptor(DbType.MYSQL));returninterceptor;}}

第四步:数据“注入” (配置 Web 过滤器)

引擎装好了,但还得有人把燃料(租户ID)塞进第一步的“背包”里。通常是在请求刚进来时处理。

代码核心:实现FilterHandlerInterceptor

@ComponentpublicclassTenantContextFilterimplementsFilter{@OverridepublicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,FilterChainchain){try{// 1. 从请求头 Header 获取 tenant-idHttpServletRequestreq=(HttpServletRequest)request;StringtenantIdStr=req.getHeader("tenant-id");if(tenantIdStr!=null){// 2. 塞进 ThreadLocal 背包TenantContextHolder.setTenantId(Long.valueOf(tenantIdStr));}// 3. 放行,执行后续业务逻辑 (Service -> Mapper -> SQL拦截器)chain.doFilter(request,response);}finally{// 4. 【重要】请求结束,清空背包,防止线程污染TenantContextHolder.clear();}}}

🌟 总结:这一套下来发生了什么?

  1. 请求进来:Filter 从 Header 拿到tenant_id=1,存入TenantContextHolder
  2. 业务查询:你写了userMapper.selectList(null)
  3. 拦截改写TenantLineInnerInterceptor拦截 SQL,调用MyTenantLineHandler
  4. 读取规则:Handler 从TenantContextHolder拿到1
  5. SQL 变身:SQL 被自动拼接为SELECT * FROM user WHERE tenant_id = 1
  6. 请求结束:Filter 清空TenantContextHolder

这就是实现“全自动多租户隔离”的完整标准流程。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/1 5:00:09

44、Red Hat Linux 9 系统网络安全与服务管理

Red Hat Linux 9 系统网络安全与服务管理 在当今数字化的时代,网络安全至关重要。对于 Red Hat Linux 9 系统而言,保障系统安全、合理管理网络服务是确保系统稳定运行的关键。本文将详细介绍如何自动运行 Tripwire 进行系统完整性检查,以及如何管理网络服务、监控服务状态和…

作者头像 李华
网站建设 2026/5/1 7:09:55

21、量子音乐、量子艺术及其感知:声音中的量子视角

量子音乐、量子艺术及其感知:声音中的量子视角 1. 量子音乐与艺术概述 在音乐领域,存在一种理想的通用乐器,它能够演奏出所有可能的经典音符,钢琴和管风琴在实际应用中或许是接近这种通用乐器的良好近似。量子音乐和量子艺术,如同量子计算(Deutsch,1985),或者以实数…

作者头像 李华
网站建设 2026/5/1 5:03:46

22、声音中的量子:量子声乐理论探索

声音中的量子:量子声乐理论探索 1 量子与声音测量基础 量子理论中的量子态是态空间中的单位长度向量,可看作具有一定概率的值的叠加。本征态是某个算符的特征态,测量过程会使概率波坍缩到某个值,即某个算符的本征值,此时系统处于该算符的本征态。概率是量子力学的关键概念…

作者头像 李华
网站建设 2026/5/1 5:02:19

27、量子世界:从纠缠到计算的探索

量子世界:从纠缠到计算的探索 高维空间与量子现象的想象 在量子物理学的发展历程中,高维空间的概念一直是一个充满挑战与想象的领域。早期,量子物理学的先驱们,如埃尔温薛定谔(Erwin Schrdinger)和路易德布罗意(Louis de Broglie),就对高维构型空间中的量子现象有着…

作者头像 李华