mybatisplus多租户插件常见问题
时间: 2025-05-23 11:12:37 浏览: 46
### MyBatisPlus 多租户插件常见问题及解决方法
#### 1. **未正确配置租户字段**
当使用 MyBatis-Plus 的多租户功能时,如果没有在 `application.yml` 文件中正确指定租户字段名,则可能导致 SQL 查询无法正常过滤数据。
解决方案:
确保在配置文件中设置了正确的租户字段名称。例如:
```yaml
tenant:
enable: true
column: tenant_id
```
此设置会告诉 MyBatis-Plus 使用哪个字段作为租户标识[^1]。
---
#### 2. **未排除特定表导致异常**
某些系统表(如字典表、菜单表等)可能不需要进行租户隔离。如果这些表被错误地应用了租户过滤器,可能会引发查询失败或其他异常行为。
解决方案:
在配置文件中明确列出需要排除的表清单。例如:
```yaml
exclusionTable:
- "sys_config"
- "sys_dict_data"
- "sys_dict_type"
```
这样可以避免对无需租户隔离的表施加额外约束[^1]。
---
#### 3. **线程上下文中缺少租户 ID**
MyBatis-Plus 的多租户机制依赖于 ThreadLocal 来存储当前请求所属的租户 ID。如果未初始化或丢失了该值,则会导致查询返回全量数据而非限定范围内的结果。
解决方案:
开发人员应在每次 HTTP 请求进入服务端之前显式设置租户 ID 到 ThreadLocal 中。可以通过拦截器完成这一操作。例如:
```java
public class TenantInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String tenantId = request.getHeader("X-Tenant-ID"); // 或者从其他地方获取
if (StringUtils.isNotBlank(tenantId)) {
TenantContext.setTenantId(tenantId); // 设置到全局变量或者自定义工具类
}
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
TenantContext.clear(); // 清理资源防止内存泄漏
}
}
```
同时需注意清理逻辑以释放占用的空间并减少潜在风险[^4]。
---
#### 4. **跨库场景下的主键冲突**
对于 SaaS 架构下支持动态切换数据库的情况,可能存在各分库间共享相同序列号生成策略的现象。一旦发生这种情况就容易造成新增记录时违反唯一性约束而出错。
解决方案之一是在设计阶段即考虑采用分布式唯一 id 生产算法代替传统 auto_increment 方式;另一种办法则是针对每套实例单独维护其内部计数器状态信息并通过编程手段同步至目标环境后再继续执行后续流程[^3]。
---
#### 5. **超级管理员权限绕过租户限制**
为了满足业务需求,有时我们需要允许部分特殊角色访问所有租户的数据。然而如果不小心遗漏相关判断条件的话很容易破坏整个系统的安全性边界设定。
解决方案建议如下所示伪代码片段所描述那样实现灵活控制机制:
```java
@Override
public Expression getExpression() {
List<String> exclusions = Arrays.asList("SUPER_ADMIN", "NO_LOGIN");
Optional<String> currentTenantOpt = getCurrentTenantFromContext();
if (!currentTenantOpt.isPresent()) {
throw new RuntimeException("Missing required parameter 'tenant_id'.");
} else if (!exclusions.contains(currentTenantOpt.get())) {
return new SingleColumn(new TableFieldInfo("tenant_id"), SqlMethod.EQUAL, currentTenantOpt.get());
} else {
return null; // 不添加任何关于 tenants 的 WHERE 子句
}
}
```
这里的关键在于识别出哪些身份应当享有例外待遇,并据此调整最终组装出来的表达式结构.
---
### 示例代码展示如何自定义 TenantLineHandler 接口
下面给出一个简单的例子说明怎样扩展默认的行为来适应更复杂的实际应用场景:
```java
@Component
public class CustomTenantLineHandler extends DefaultTenantLineHandler {
private static final Set<String> EXCLUSION_TENANTS = Collections.unmodifiableSet(
Sets.newHashSet("SUPER_ADMIN", "NO_LOGIN"));
@Override
protected Collection<?> getExcludeTables() {
return Lists.newArrayList("sys_config", "sys_dict_data", ...);
}
@Override
public Expression getExpression() {
String tenantId = TenantContextHolder.getTenantId();
if (EXCLUSION_TENANTS.contains(tenantId)) {
return null;
}
return super.getExpression();
}
}
```
上述实现方式不仅保留了原有功能还增加了必要的灵活性以便应对更多变种情况的发生[^4].
---
阅读全文
相关推荐


















