概要
mybatis plus3.1.0使用多租户插件和3.5有点区别,不能直接通过MybatisPlusInterceptor 进行配置。mybatis plus 3.1.0版本的AbstractSqlParserHandler 只有两个实现
所以 想要使用租户解析器 需要借助PaginationInterceptor 分页拦截器,把TenantSqlParser这个sql解析器加载到PaginationInterceptor 这个拦截器里进行处理。
详细
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.0</version>
</dependency>
通过实现TenantHandler 接口 自定义租户处理器
public class MyTenantLineHandler implements TenantHandler {
/**
* 租户字段名
*/
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<>();
static {
IGNORE_TENANT_TABLES.add("manage_user");
}
/**
* 获取租户ID值
*/
@Override
public Expression getTenantId() {
System.out.println("获取租户ID值");
//获取登录用户的租户ID
Long loginUserTenantId = getLoginUserTenantId();
if (loginUserTenantId == null){
loginUserTenantId = DEFAULT_TENANT_ID;
}
return new LongValue(loginUserTenantId);
}
/**
* 租户字段名,默认是tenant_id,如果想改成其他字段,在这里返回即可
*/
@Override
public String getTenantIdColumn() {
return SYSTEM_TENANT_ID;
}
/**
* 不需要进行租户隔离的表,在这里返回true
*/
@Override
public boolean doTableFilter(String tableName) {
if (IGNORE_TENANT_TABLES.contains(tableName)){
//不需要租户隔离
return true;
}else {
//需要租户隔离
return false;
}
}
public Long getLoginUserTenantId(){
//模拟获取登录用户的租户ID,可以从登录用户缓存信息中获取
return 2L;
}
分页拦截器, 租户核心配置:TenantSqlParser
@Configuration
@MapperScan(basePackages = {"com.test.*.business.*.mapper"})
public class MybatisPlusConfig {
//3.1.0 版本 通过分页拦截器配置
@Bean
public PaginationInterceptor paginationInterceptor() {
// 租户 SQL 解析器
TenantSqlParser tenantSqlParser = new TenantSqlParser();
tenantSqlParser.setTenantHandler(new MyTenantLineHandler());
//分页拦截器
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
// paginationInterceptor.setLocalPage(false);// 开启 PageHelper 的支持
List<ISqlParser> sqlParserList = new ArrayList<>();
// 攻击 SQL 阻断解析
sqlParserList.add(new BlockAttackSqlParser());
// 增加租户处理
sqlParserList.add(tenantSqlParser);
// 加入解析链
paginationInterceptor.setSqlParserList(sqlParserList);
return paginationInterceptor;
}
// 3.5.0 版本可以这样配置
// 新多租户插件配置,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存万一出现问题
// @Bean
// public MybatisPlusInterceptor mybatisPlusInterceptor() {
// MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// // 攻击 SQL 阻断解析器、加入解析链
// interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
// // 添加多租户插件
// interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(new MyTenantLineHandler()));
// //如果配置多个插件,切记分页最后添加,如果有多数据源可以不配具体类型 否则都建议配上具体的DbType
// //用了分页插件必须设置 MybatisConfiguration#useDeprecatedExecutor = false
// PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.POSTGRE_SQL);
// //设置单页分页最大数量
// paginationInnerInterceptor.setMaxLimit(500L);
// interceptor.addInnerInterceptor(paginationInnerInterceptor);
// return interceptor;
// }
// @Bean
// public ConfigurationCustomizer configurationCustomizer() {
// return configuration -> configuration.setUseDeprecatedExecutor(false);
// }
}
配置结束后,就能成功使用了。
注:如果部分SQL不需要加上租户ID,除了在TenantHandler 配置过滤,还可以通过租户注解 @SqlParser(filter = true) 的形式过滤特定的sql,目前该注解只能作用于Mapper的方法上
总结
多租户识别:插件通过拦截器机制,在 SQL 语句执行之前,获取当前请求的租户 ID。
SQL 语句动态修改:通过动态拼接 SQL ,在原有 SQL 语句中加入租户 ID ,实现租户数据的隔离。