当前位置: 首页 > article >正文

MyBatis Plus多租户实战:如何用TenantLineHandler实现数据隔离(附完整代码)

MyBatis Plus多租户架构深度实践从TenantLineHandler到生产级解决方案在当今SaaS服务盛行的时代多租户架构已成为企业级应用的标配需求。作为Java生态中最受欢迎的ORM框架之一MyBatis Plus通过TenantLineHandler提供了一套优雅的多租户解决方案。本文将带您深入实践不仅涵盖基础实现更会分享我在多个大型项目中总结出的实战经验与避坑指南。1. 多租户架构的核心设计考量多租户Multi-tenancy的本质是在单一应用实例中为多个客户租户提供服务同时确保数据隔离。在开始编码前我们需要明确几个关键设计决策三种主流的多租户数据隔离方案对比方案类型数据库级别表设计优缺点独立数据库每个租户独立数据库相同表结构隔离性最强成本最高共享数据库独立Schema同一数据库不同Schema相同表结构中等隔离中等成本共享数据库共享表同一数据库同一Schema增加tenant_id列成本最低需严格代码控制提示90%的中大型SaaS项目会选择共享数据库共享表方案这也是MyBatis Plus TenantLineHandler主要支持的场景。在实际项目中我们还需要考虑租户标识的存储与传递建议使用ThreadLocal公共表与租户表的区分策略分布式环境下的租户上下文一致性性能影响评估特别是关联查询场景2. TenantLineHandler的完整实现剖析让我们从基础实现开始逐步构建一个生产可用的多租户解决方案。2.1 租户上下文管理首先需要建立租户信息的传递机制。我推荐使用ThreadLocal结合Filter的方案public class TenantContext { private static final ThreadLocalString CURRENT_TENANT new ThreadLocal(); public static void setCurrentTenant(String tenantId) { CURRENT_TENANT.set(tenantId); } public static String getCurrentTenant() { return CURRENT_TENANT.get(); } public static void clear() { CURRENT_TENANT.remove(); } } // 在Spring Web拦截器中设置租户ID public class TenantInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { String tenantId request.getHeader(X-Tenant-ID); if (StringUtils.isNotBlank(tenantId)) { TenantContext.setCurrentTenant(tenantId); } return true; } Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { TenantContext.clear(); } }2.2 核心TenantLineHandler实现以下是增强版的CustomTenantLineHandler实现包含多项生产环境必需的优化public class EnhancedTenantLineHandler implements TenantLineHandler { // 租户ID列名可配置化 private String tenantIdColumn tenant_id; // 忽略租户过滤的表名集合 private SetString ignoreTables new HashSet(Arrays.asList( system_config, common_code, metadata_table )); Override public Expression getTenantId() { String tenantId TenantContext.getCurrentTenant(); if (StringUtils.isBlank(tenantId)) { throw new BusinessException(租户上下文不存在); } return new StringValue(tenantId); } Override public String getTenantIdColumn() { return tenantIdColumn; } Override public boolean ignoreTable(String tableName) { // 动态判断是否忽略租户过滤 return ignoreTables.contains(tableName.toLowerCase()) || tableName.startsWith(global_); } // 支持动态配置 public void setTenantIdColumn(String tenantIdColumn) { this.tenantIdColumn tenantIdColumn; } public void setIgnoreTables(String tables) { this.ignoreTables Arrays.stream(tables.split(,)) .map(String::trim) .collect(Collectors.toSet()); } }2.3 MyBatis Plus配置集成在最新版本的MyBatis Plus中配置方式有所变化Configuration public class MybatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); // 租户插件 TenantLineInnerInterceptor tenantInterceptor new TenantLineInnerInterceptor(); tenantInterceptor.setTenantLineHandler(enhancedTenantLineHandler()); interceptor.addInnerInterceptor(tenantInterceptor); interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); return interceptor; } Bean public EnhancedTenantLineHandler enhancedTenantLineHandler() { EnhancedTenantLineHandler handler new EnhancedTenantLineHandler(); handler.setTenantIdColumn(tenant_code); handler.setIgnoreTables(system_config,common_code); return handler; } }3. 高级场景与性能优化多租户实现后我们还需要解决一些进阶问题。3.1 分布式系统下的租户传递在微服务架构中租户信息需要跨服务传递。建议采用以下方案HTTP头传递所有服务间调用携带X-Tenant-ID头MQ消息扩展在消息属性中添加tenantId字段Feign拦截器自动处理租户信息public class TenantFeignInterceptor implements RequestInterceptor { Override public void apply(RequestTemplate template) { String tenantId TenantContext.getCurrentTenant(); if (StringUtils.isNotBlank(tenantId)) { template.header(X-Tenant-ID, tenantId); } } }3.2 多租户下的SQL性能优化租户条件自动追加可能影响查询性能特别是多表JOIN查询大数据量表的分页查询复杂子查询场景优化建议为tenant_id列建立索引避免全表扫描的租户查询对大数据量表考虑分区表策略定期执行租户数据统计任务-- 建议的索引创建方式 CREATE INDEX idx_tenant ON user(tenant_id); CREATE INDEX idx_tenant_status ON order(tenant_id, status);4. 测试策略与常见问题排查确保多租户功能正确性需要特别的测试方法。4.1 单元测试方案SpringBootTest public class TenantTest { Autowired private UserMapper userMapper; Test public void testTenantIsolation() { // 模拟租户A上下文 TenantContext.setCurrentTenant(tenantA); userMapper.insert(new User(User1)); // 模拟租户B上下文 TenantContext.setCurrentTenant(tenantB); Assert.assertEquals(0, userMapper.selectCount(null)); // 验证公共表不受影响 long configCount systemConfigMapper.selectCount(null); Assert.assertTrue(configCount 0); } }4.2 常见问题排查清单SQL中缺少租户条件检查TenantLineHandler是否正确配置验证表名是否被意外过滤跨租户数据泄露检查ThreadLocal是否及时清理验证异步任务中的上下文传递性能下降明显检查tenant_id列索引分析执行计划公共表被错误过滤验证doTableFilter逻辑检查表名大小写问题在最近的一个电商平台项目中我们遇到了一个典型问题在批量导入数据时由于没有显式设置租户ID导致数据被错误地归属到默认租户。最终通过添加以下检查代码解决了问题public void batchImport(ListProduct products) { if (TenantContext.getCurrentTenant() null) { throw new IllegalStateException(批量操作必须指定租户); } // 实际导入逻辑 }

相关文章:

MyBatis Plus多租户实战:如何用TenantLineHandler实现数据隔离(附完整代码)

MyBatis Plus多租户架构深度实践:从TenantLineHandler到生产级解决方案 在当今SaaS服务盛行的时代,多租户架构已成为企业级应用的标配需求。作为Java生态中最受欢迎的ORM框架之一,MyBatis Plus通过TenantLineHandler提供了一套优雅的多租户解…...

密码学开发实战:如何在Windows上快速搭建PBC+GMP开发环境(含VS2019适配方案)

密码学开发实战:Windows下PBC与GMP开发环境高效配置指南 1. 环境搭建前的准备工作 在开始配置PBC和GMP开发环境之前,我们需要先了解这两个库的基本情况。PBC(Pairing-Based Cryptography)库是一个专门用于双线性对密码学运算的开源…...

AI编程助手:利用Z-Image-Turbo_Sugar脸部Lora生成代码注释与文档所需的头像素材

AI编程助手:利用Z-Image-Turbo_Sugar脸部Lora生成代码注释与文档所需的头像素材 1. 引言:当代码文档遇上个性化头像 你有没有发现,很多开源项目的README文档或者技术博客里,作者头像要么是默认的灰色剪影,要么就是五…...

CTF新手必看:从ROT13到Base85的套娃编码实战解析(附完整脚本)

CTF新手必看:从ROT13到Base85的套娃编码实战解析(附完整脚本) 当你第一次接触CTF竞赛中的编码题目时,看到那些层层嵌套的加密字符串,是不是感觉像在拆俄罗斯套娃?本文将带你从零开始,手把手破解…...

Qwen3-0.6B-FP8保姆级教程:模型加载失败时的7类错误码速查与修复指南

Qwen3-0.6B-FP8保姆级教程:模型加载失败时的7类错误码速查与修复指南 1. 引言:为什么你的模型加载总失败? 如果你正在尝试部署Qwen3-0.6B-FP8这个轻量化对话工具,大概率会遇到一个让人头疼的问题:模型加载失败。控制…...

AWS CDK Examples 企业级应用:大规模云基础设施的架构设计

AWS CDK Examples 企业级应用:大规模云基础设施的架构设计 【免费下载链接】aws-cdk-examples Example projects using the AWS CDK 项目地址: https://gitcode.com/gh_mirrors/aw/aws-cdk-examples AWS CDK Examples 是一个强大的开源项目,提供了…...

影刀收购Automa:RPA生态融合的机遇与挑战

1. 影刀收购Automa的背景与意义 最近RPA圈子里最热的话题莫过于影刀收购Automa这件事了。作为一个在自动化领域摸爬滚打多年的老手,我第一反应是:这绝对是个值得深入探讨的行业事件。影刀作为国内RPA领域的头部玩家,收购了国外知名的开源浏览…...

Ubuntu上nvidia-smi报错Driver/library version mismatch?不用重启的3个排查与修复步骤

Ubuntu上nvidia-smi报错Driver/library version mismatch的深度修复指南 当你正准备开始一天的深度学习训练或图形渲染工作时,突然发现nvidia-smi命令报出"Driver/library version mismatch"错误,这无疑是令人沮丧的。本文将带你深入理解这个问…...

手把手教你用yum在openEuler上安全升级OpenSSH 10.0p1(附完整命令集)

手把手教你用yum在openEuler上安全升级OpenSSH 10.0p1(附完整命令集) 最近在维护openEuler服务器时,发现系统自带的OpenSSH版本存在一些已知的安全漏洞。作为系统管理员,我深知SSH服务的安全性直接关系到整个服务器的访问安全。经…...

华为路由器帧中继配置实战:Hub-and-Spoke模式下RIP与OSPF的坑我都踩过了

华为路由器帧中继配置实战:Hub-and-Spoke模式下RIP与OSPF的坑我都踩过了 在企业级网络部署中,帧中继技术虽然逐渐被MPLS等新技术取代,但在某些特定场景下仍然是不可或缺的解决方案。特别是在Hub-and-Spoke拓扑结构中,帧中继的配置…...

WuliArt Qwen-Image Turbo显存优化部署:VAE分块编码+CPU卸载实测报告

WuliArt Qwen-Image Turbo显存优化部署:VAE分块编码CPU卸载实测报告 1. 引言:当高清文生图遇上个人显卡 如果你尝试过在个人电脑上运行最新的文生图模型,大概率会遇到一个头疼的问题:显存爆炸。动辄需要40G、80G显存的模型&…...

TeslaMate容器日志导出:保存与分析历史记录的实用命令

TeslaMate容器日志导出:保存与分析历史记录的实用命令 【免费下载链接】teslamate 项目地址: https://gitcode.com/gh_mirrors/tes/teslamate TeslaMate是一款功能强大的自托管Tesla车辆数据记录器,通过Docker容器部署,能够持续监控和…...

Qt 6.4 + Limereport 1.7.9 实战:5分钟搞定动态报表生成(附Python绑定教程)

Qt 6.4 Limereport 1.7.9 实战:Python绑定下的动态报表生成指南 在数据处理和业务系统开发中,报表生成是一个永恒的需求。传统方案往往需要依赖复杂的商业软件或繁琐的手动操作,而Qt与Limereport的组合为开发者提供了一条高效路径。本文将聚…...

Pixel Mind Decoder 安全与隐私考量:处理用户文本数据的合规性指南

Pixel Mind Decoder 安全与隐私考量:处理用户文本数据的合规性指南 1. 为什么数据安全与隐私如此重要 想象一下,你正在开发一款情绪分析应用,能够通过分析用户输入的文本内容来判断他们的情绪状态。这个功能听起来很酷,但背后隐…...

Clappr流媒体支持:HLS、DASH等格式完全指南

Clappr流媒体支持:HLS、DASH等格式完全指南 【免费下载链接】clappr :clapper: An extensible media player for the web. 项目地址: https://gitcode.com/gh_mirrors/cl/clappr Clappr是一款功能强大的Web媒体播放器,以其高度可扩展性和对多种流…...

FUTURE POLICE模型API网络安全防护配置指南

FUTURE POLICE模型API网络安全防护配置指南 最近在帮一个朋友部署他们团队的FUTURE POLICE模型服务,准备对外提供API。部署本身挺顺利,但聊到安全防护时,我发现他们想得有点简单了——直接把服务端口暴露在公网上,觉得有个密码登…...

#AI原生安全,全球首个软件供应链安全开源社区OpenSCA

在“软件定义万物”的时代,软件供应链开源化使得各个环节不可避免地受到开源应用的影响,尤其是开源应用的安全性,将直接影响软件供应链的安全性。除开源应用开发者在开发过程中无意识地引入的安全缺陷之外,还可能会存在开发者有目…...

基于C++高性能调用EasyAnimateV5-7b-zh-InP核心引擎

基于C高性能调用EasyAnimateV5-7b-zh-InP核心引擎 1. 引言 想象一下这样的场景:你有一个电商平台,每天需要处理成千上万的商品图片。如果能让这些静态的商品图"动起来",变成几秒钟的展示视频,转化率会提升多少&#x…...

造相-Z-Image-Turbo亚洲美女LoRA案例:教育课件插图/医疗科普配图/法律文书图解

造相-Z-Image-Turbo亚洲美女LoRA案例:教育课件插图/医疗科普配图/法律文书图解 1. 项目概述 造相-Z-Image-Turbo 亚洲美女LoRA是一个基于Z-Image-Turbo模型的图片生成Web服务,专门针对亚洲女性形象生成进行了优化。该项目新增了对LoRA模型laonansheng/…...

#AI原生安全,软件供应链安全策略与选型,开发者的最佳选择

随着数字化转型进入深水区,容器、中间件、微服务、DevOps等新技术的演进,数字供应链愈发复杂,全链路安全防护难度不断加大。悬镜安全子芽带领公司安全团队攻坚克难近十年,在业界定义了代码疫苗技术,完成代码疫苗技术在…...

使用 VSCode 接入 DeepSeek V3 平替 Cursor 与 Trae 的 AI 编程方案

在深入体验 AI 编程的这几天里,我深刻感受到,程序员们完全可以借助 AI 的力量来提升工作效率,节省脑力。 平时需要一天完成的工作量,现在半天都不用就做完了,在做逻辑比较能用简单的事(前端、脚本或者后端…...

STM32与淘晶驰串口屏通信:如何正确使用转义字符避免txt控件显示问题

STM32与淘晶驰串口屏通信:转义字符应用全解析与实战避坑指南 在嵌入式系统开发中,人机交互界面(HMI)的设计往往决定着产品的用户体验。淘晶驰串口屏以其易用性和性价比,成为众多STM32开发者的首选。然而,当开发者尝试将动态数据发…...

告别输入法乱码!ArchLinux + GNOME 桌面下 Fcitx5 的保姆级配置与美化全攻略

ArchLinux GNOME 桌面下 Fcitx5 输入法的终极配置与视觉优化指南 在 Linux 桌面环境中配置中文输入法一直是许多用户的痛点,尤其是对于 ArchLinux 这样需要手动配置的发行版。本文将带你从零开始,在 GNOME 桌面环境下打造一个既稳定又美观的 Fcitx5 输入…...

3GPP会议提案追踪指南:如何快速找到RAN工作组的最新讨论内容?

3GPP会议提案追踪实战指南:从文档架构到高效检索 在移动通信标准制定的浩瀚海洋中,3GPP的会议提案就像是一座座灯塔,指引着技术演进的方向。作为一名经常需要追踪RAN工作组最新讨论内容的通信工程师,我深刻体会到快速定位关键提案…...

学习记录:从零开始学AI(四)——Scikit-learn加州房价机器学习例子学习笔记-在此基础上更换自己的数据集

后记:之前一直以为用的是TensorFlow,原来我用的是 Scikit-learn。两者都可以实现机器学习。前者更适合实现深度神经网络。更正题目。 2025.04.22 加州房价机器学习例子已经调通,下一步更换自己的数据集。数据集先随便构建吧,不是真实的,后续再更换真实的。 加州房价数据…...

高性能字体处理架构设计:FontTools 4.62.2版本深度解析与最佳实践

高性能字体处理架构设计:FontTools 4.62.2版本深度解析与最佳实践 【免费下载链接】fonttools A library to manipulate font files from Python. 项目地址: https://gitcode.com/gh_mirrors/fo/fonttools FontTools是一个用于操作字体文件的强大Python库&am…...

Deepfake Offensive Toolkit开源项目年度财务报告:收支与预算

Deepfake Offensive Toolkit开源项目年度财务报告:收支与预算 【免费下载链接】dot The Deepfake Offensive Toolkit 项目地址: https://gitcode.com/gh_mirrors/dot/dot Deepfake Offensive Toolkit(简称dot)作为一款专注于实时深度伪…...

RexUniNLU模型量化实战:FP16与INT8精度对比

RexUniNLU模型量化实战:FP16与INT8精度对比 想用大模型做点实际项目,但一看显存占用就头疼?这大概是很多开发者入门AI时的第一道坎。模型是好模型,功能也强大,但动辄几十GB的显存需求,直接把个人电脑和普通…...

ESP8266电压检测避坑指南:如何解决WiFi干扰导致的ADC读数不准问题

ESP8266电压检测避坑指南:如何解决WiFi干扰导致的ADC读数不准问题 在物联网设备开发中,ESP8266因其高性价比和内置WiFi功能而广受欢迎。然而,许多开发者在使用其内置ADC进行电压检测时,都会遇到一个令人头疼的问题——WiFi模块工作…...

Datashader 大规模数据可视化流水线:从海量数据到高清图像的完整指南

Datashader 大规模数据可视化流水线:从海量数据到高清图像的完整指南 【免费下载链接】datashader Quickly and accurately render even the largest data. 项目地址: https://gitcode.com/gh_mirrors/da/datashader 在数据科学和可视化领域,处理…...