MybatisPlus源码解析4:租户拦截器

文章解析了MybatisPlus中的租户拦截器工作原理,包括拦截器如何在查询时动态添加租户信息,以及解析和构建SQL表达式的过程。重点介绍了`TenantLineInnerInterceptor`的`beforeQuery`方法和`buildTableExpression`方法的应用。

本文主要是对租户拦截器进行解析,不同租户之间的数据隔离的,一个租户的数据查询、更新、插入、删除操作都不会对他的租户的数据产生任何影响

1.项目结构

源码地址:https://github.com/lmhdsad/mybatis-plus-source-study/tree/main/mybatis-plus-plugin-tenant

项目结构:
在这里插入图片描述

2. 源码分析 MybatisPlusInterceptor

@SuppressWarnings({
   
   "rawtypes"})
@Intercepts(
    {
   
   
        @Signature(type = StatementHandler.class, method = "prepare", args = {
   
   Connection.class, Integer.class}),
        @Signature(type = StatementHandler.class, method = "getBoundSql", args = {
   
   }),
        @Signature(type = Executor.class, method = "update", args = {
   
   MappedStatement.class, Object.class}),
        @Signature(type = Executor.class, method = "query", args = {
   
   MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
        @Signature(type = Executor.class, method = "query", args = {
   
   MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
    }
)
public class MybatisPlusInterceptor implements Interceptor {
   
   

    @Setter
    private List<InnerInterceptor> interceptors = new ArrayList<>();

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
   
   
        Object target = invocation.getTarget();
        Object[] args = invocation.getArgs();
        if (target instanceof Executor) {
   
   
            final Executor executor = (Executor) target;
            Object parameter = args[1];
            boolean isUpdate = args.length == 2;
            MappedStatement ms = (MappedStatement) args[0];
            if (!isUpdate && ms.getSqlCommandType() == SqlCommandType.SELECT) {
   
   
                RowBounds rowBounds = (RowBounds) args[2];
                ResultHandler resultHandler = (ResultHandler) args[3];
                <
### MyBatisPlus 中分页拦截器租户拦截器的功能集成 #### 功能概述 MyBatisPlus 提供了强大的插件机制,其中 `MybatisPlusInterceptor` 是核心组件之一。通过它,可以轻松实现诸如分页、多租户等功能[^1]。 为了同时支持分页和多租户功能,可以通过配置 `MybatisPlusInterceptor` 并注册多个子拦截器来完成需求。以下是具体实现方式: --- #### 配置分页拦截器租户拦截器Spring Boot 项目中,通常会在启动类或者配置类中初始化并注册这些拦截器。以下是一个完整的示例代码: ```java import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MyBatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 注册分页拦截器 PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor(); interceptor.addInnerInterceptor(paginationInterceptor); // 注册多租户拦截器 TenantLineInnerInterceptor tenantLineInterceptor = new TenantLineInnerInterceptor(new CustomTenantHandler()); tenantLineInterceptor.setIgnoreTable(Arrays.asList("sys_user", "sys_role")); // 可选:忽略某些表的租户过滤 interceptor.addInnerInterceptor(tenantLineInterceptor); return interceptor; } } ``` 上述代码中: - 使用 `PaginationInnerInterceptor` 来启用分页功能[^3]。 - 使用 `TenantLineInnerInterceptor` 来启用多租户功能,并传入自定义的租户处理器 `CustomTenantHandler`[^2]。 --- #### 自定义租户处理逻辑 多租户的核心在于动态注入 SQL 的 WHERE 子句中的租户条件。下面是一个简单的租户处理器实现: ```java import com.baomidou.mybatisplus.core.handlers.TenantLineHandler; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.StringValue; import java.util.Collections; public class CustomTenantHandler implements TenantLineHandler { private static final String TENANT_ID_COLUMN_NAME = "tenant_id"; @Override public Expression getTenantId(boolean where) { // 返回当前线程绑定的租户 ID (假设存储在 ThreadLocal 中) String currentTenantId = CurrentUserContext.getTenantId(); // 获取当前用户的租户ID return new StringValue(currentTenantId); } @Override public String getTenantIdColumn() { return TENANT_ID_COLUMN_NAME; // 数据库中用于区分租户的字段名 } @Override public boolean openTENANT_LINE(String tableName) { // 判断哪些表需要开启多租户模式 return !tableName.startsWith("sys_"); // sys_* 表不参与多租户过滤 } } ``` 此代码片段展示了如何通过 `getTenantId()` 方法获取当前租户 ID,并将其作为 SQL 查询的一部分自动附加到查询语句中。 --- #### 示例场景 假设有如下数据库表结构: | 表名 | 字段 | |------------|----------------| | order_info | id, name, price, tenant_id | 当执行以下分页查询时: ```sql SELECT * FROM order_info LIMIT 0, 10; ``` 实际生成的 SQL 将变为: ```sql SELECT * FROM order_info WHERE tenant_id = 'current_tenant' LIMIT 0, 10; ``` 这表明分页和多租户功能已成功集成。 --- #### 注意事项 1. **版本兼容性** 确保使用的 MyBatisPlus 版本不低于 3.4.0,因为低版本可能缺少部分功能或存在 Bug。 2. **性能优化** 对于高并发场景,建议缓存租户信息以减少频繁调用开销。 3. **异常处理** 如果未设置租户 ID 或者租户 ID 不合法,则可能导致查询失败。因此需提前校验输入参数。 ---
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值