当前位置:   article > 正文

Mybatis-plus多租户插件

mybatis-plus多租户插件

Mybatis-plus多租户插件

Mybatis-plus多租户插件是一种用于实现多租户功能的插件,它基于Mybatis框架,通过拦截器机制实现对多租户的支持。该插件的核心组件包括TenantHandler和TenantInterceptor,其中TenantHandler用于处理租户相关的逻辑,如获取租户ID、设置租户信息等;而TenantInterceptor则用于拦截需要处理多租户的SQL语句,并在SQL中添加租户条件。

官方说明:

  1. 多租户 != 权限过滤,不要乱用,租户之间是完全隔离的!!!
  2. 启用多租户后所有执行的method的sql都会进行处理.
  3. 自写的sql请按规范书写(sql涉及到多个表的每个表都要给别名,特别是 inner join 的要写标准的 inner join

实现原理

Mybatis-plus多租户插件的实现原理主要基于Mybatis的拦截器(Interceptor)机制,通过拦截器在需要执行的sql后面自动添加租户的查询条件,实现多租户功能。具体来说,Mybatis-plus提供了TenantLineInnerInterceptor租户处理器来实现多租户功能。在启用多租户后,所有执行的method的sql都会被处理,即自写的sql需要按照规范书写(sql涉及到多个表的每个表都要给别名,特别是inner join的要写标准的inner join)。

简单来说,Mybatis-plus多租户插件通过自定义Mybatis拦截器,在执行sql时自动添加租户的查询条件,实现多租户功能。

和基于物理隔离(分表)实现多租户不同,基于逻辑隔离(租户标识列,tenant_id)实现多租户是在每一张表中添加一个租户标识列(tenant_id),通过该列来区分各个租户的数据。

TenantLineInnerInterceptor插件也是基于逻辑隔离(租户标识列,tenant_id)实现多租户的,只不过它给我们封装了部分逻辑,让我们不用再SQL中显示地指定tenant_id作为条件,它会自动为我们拼接。

使用

1、自定义TenantLineHandler

下面是TenantLineHandler 接口的定义,主要是用于获取租户ID和表是否需要需要租户隔离判断

/**
 * 租户处理器( TenantId 行级 )
 *
 * @author hubin
 * @since 3.4.0
 */
public interface TenantLineHandler {

    /**
     * 获取租户 ID 值表达式,只支持单个 ID 值
     * <p>
     *
     * @return 租户 ID 值表达式
     */
    Expression getTenantId();

    /**
     * 获取租户字段名
     * <p>
     * 默认字段名叫: tenant_id
     *
     * @return 租户字段名
     */
    default String getTenantIdColumn() {
        return "tenant_id";
    }

    /**
     * 根据表名判断是否忽略拼接多租户条件
     * <p>
     * 默认都要进行解析并拼接多租户条件
     *
     * @param tableName 表名
     * @return 是否忽略, true:表示忽略,false:需要解析并拼接多租户条件
     */
    default boolean ignoreTable(String tableName) {
        return false;
    }

    /**
     * 忽略插入租户字段逻辑
     *
     * @param columns        插入字段
     * @param tenantIdColumn 租户 ID 字段
     * @return
     */
    default boolean ignoreInsert(List<Column> columns, String tenantIdColumn) {
        return columns.stream().map(Column::getColumnName).anyMatch(i -> i.equalsIgnoreCase(tenantIdColumn));
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

自定义的TenantLineHandler ,我们需要按照自己的实际情况来定义自己的租户字段和获取

@Slf4j
@Component
public class MyTenantLineHandler implements TenantLineHandler {

    /**
     * 租户字段名
     */
    private static final String SYSTEM_TENANT_ID = "tenant_id";

    /**
     * 默认的租户ID
     */
    public static final Long DEFAULT_TENANT_ID = 1L;

    /**
     * 需要过滤的表
     */
    private static final List<String> IGNORE_TENANT_TABLES = new ArrayList<>();

    /**
     * 获取租户ID值
     * @return
     */
    @Override
    public Expression getTenantId() {
        //获取登录用户的租户ID
        Long loginUserTenantId = getLoginUserTenantId();
        if (loginUserTenantId == null){
            loginUserTenantId = DEFAULT_TENANT_ID;
        }
        return new LongValue(loginUserTenantId);
    }

    /**
     * 租户字段名,默认是tenant_id,如果想改成其他字段,在这里返回即可
     * @return
     */
    @Override
    public String getTenantIdColumn() {
        return SYSTEM_TENANT_ID;
    }

    /**
     * 有不需要进行租户隔离的表,在这里返回true
     * @param tableName
     * @return
     */
    @Override
    public boolean ignoreTable(String tableName) {
        return IGNORE_TENANT_TABLES.contains(tableName);
    }


    public Long getLoginUserTenantId(){
        //模拟获取登录用户的租户ID,实际项目可以从登录用户缓存信息中获取
        return 1L;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

2、添加租户ID字段

我们的表和实体类都需要添加上租户ID字段

表字段

  `tenant_id` bigint(20) NOT NULL COMMENT '多租户下的租户ID',
  • 1

实体字段

   @TableField("tenant_id")
    private Long tenantId;
  • 1
  • 2

3、注册mybatisplus的多租户实现到 MybatisPlusInterceptor

@Configuration
public class MybatisPlusConfig {

    /**
     * 添加MP插件
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 添加多租户插件
        interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(new MyTenantLineHandler()));
        //如果配置多个插件,切记分页最后添加,如果有多数据源可以不配具体类型 否则都建议配上具体的DbType
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
        //设置单页分页最大数量
        paginationInnerInterceptor.setMaxLimit(500L);
        interceptor.addInnerInterceptor(paginationInnerInterceptor);
        return interceptor;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

完成上面配置之后,Mybatisplus就会帮我们在增删改查的所有操作都给拼接上携带租户条件。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/407545
推荐阅读
相关标签
  

闽ICP备14008679号