mybatis-plus配置租户隔离和分页插件教程及遇到的坑
- 先说分页插件配置:
- 官网交代的很清除,细节处理都被封装好了,我们只需要在配置类加入下面代码就完成了分页插件的装配。
/**
* 添加分页插件
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 如果配置多个插件, 切记分页最后添加
// 如果有多数据源可以不配具体类型, 否则都建议配上具体的 DbType
return interceptor;
}
这里贴图官网(https://baomidou.com/plugins/tenant/)的配置代码:
- 如何使用呢?
- 答:配置了分页插件后,在*Mapper.xml中如果有分页需求,那么不需要自己实现count();去查总数,只需要在参数中传入Page<?> page, 就行了,mybatis-plus的分页插件会自动配置count();并将相应的结果封装到Page的实现中去。具体传参代码如下:
/**
* 查询列表
*
* @param page 分页对象
* @param params 筛选条件
* @return 分页列表
*/
List<?> findList(Page<?> page, @Param("params") Map<String, Object> params);
/**
* 如果想要获取条件筛选的总数,只需要调用:page.getTotal()即可
*/
至此分页插件配置完成
- 再来说说租户隔离插件配置
- 官网交代的也很清楚,第一步先创建一个租户参数配置的处理器:
//这个是官方的默认配置
@Component
public class CustomTenantHandler implements TenantLineHandler {
@Override
public Expression getTenantId() {
// 假设有一个租户上下文,能够从中获取当前用户的租户
Long tenantId = TenantContextHolder.getCurrentTenantId();
// 返回租户ID的表达式,LongValue 是 JSQLParser 中表示 bigint 类型的 class
return new LongValue(tenantId);;
}
@Override
public String getTenantIdColumn() {
return "tenant_id";
}
@Override
public boolean ignoreTable(String tableName) {
// 根据需要返回是否忽略该表
return false;
}
}
//这里是我自定义了一部分参数的配置
@Component
public class CustomTenantHandler implements TenantLineHandler {
//这东西就是一个属性存储的工具类
@Autowired
TenantProperties tenantProperties;
@Override
public Expression getTenantId() {
// 假设有一个租户上下文,能够从中获取当前用户的租户,这个TenantContextHolder代码后面我会贴出来,他的主要作用就是存储当前请求的租户标识,比如tenant_id
String tenantId = TenantContextHolder.getTenant();
// 返回租户ID的表达式
return new StringValue(tenantId);
}
@Override
public String getTenantIdColumn() {
//这里配置租户字段名,和数据库的租户字段保持一致即可
return tenantProperties.getFieldName();
}
@Override
public boolean ignoreTable(String tableName) {
// 根据需要返回是否忽略该表,这里的List<String> ignoreTables 是一个携带MySQL表名称
//的List,tableName就是当前请求所访问的表名称
List<String> ignoreTables = tenantProperties.getIgnoreTable();
return !ignoreTables.isEmpty() && ignoreTables.contains(tableName);
}
}
//租户id存储的工具类
public class TenantContextHolder {
/**
* 支持父子线程之间的数据传递
*/
private static final ThreadLocal<String> CONTEXT = new TransmittableThreadLocal<>();
//这个用来存租户id
public static void setTenant(String tenant) {
CONTEXT.set(tenant);
}
//这个用来获取已经存储的租户id
public static String getTenant() {
return CONTEXT.get();
}
//这个用来清除当前线程存储的租户id。一般而言,对于租户id的set应该在请求处理前的拦截器中,
//而请求处理完成后的拦截器应该将当前请求存储的租户id清除,避免内存泄漏
public static void clear() {
CONTEXT.remove();
}
}
//这里贴一个关于租户默认属性的常量类
@Setter
@Getter
@Component
@ConfigurationProperties(prefix = "ilycq.tenant")
public class TenantProperties {
/**
* 是否开启多租户
*/
private Boolean enable = false;
/**
* 开启的租户类型(client,org),默认client
*/
private String type = "org";
/**
* 租户对应字段名,默认tenant_id
*/
private String fieldName = "";
/**
* 配置不进行多租户隔离的表名
*/
private List<String> ignoreTable = new ArrayList<>();
}
- 第二步,将上面创建好的租户处理器加入配置类中的MybatisPlusInterceptor拦截器,代码如下:
@SpringBootConfiguration
public class MybatisPlusAutoConfigure {
@Autowired
private CustomTenantHandler customTenantHandler;
@Autowired
private TenantProperties tenantProperties;
/**
* 插件配置
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
if (tenantProperties.getEnable()) {
//注册租户插件
interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(customTenantHandler));
}
//注册分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
到这里分页插件和租户隔离就都配置成功了
- tips
- 如果只想给某一条sql过滤租户配置,使用注解 @InterceptorIgnore(tenantLine = “1”)
@InterceptorIgnore(tenantLine = "1")
List<?> getWholeList(@Param("params") Map<String, Object> params);
- 讲一下我遇到的坑:
- 首次配置完租户和分页插件后,在测试时发现分页列表中的总条数和 page.getTotal(); 的数值不同,我大为震惊,赶紧上百度图书馆博览群书,找了一圈,试了许多方法,然;并;卵(然而并没有什么卵用),又在官网仔细找了找,发现官方也没有交代。
- 还好过了不多一会儿,歪打正着的解决了。
- 说说解决方案:
- 出现问题的原因很清楚,就是在查询分页列表的时候,查询列表的sql中插入了租户,但是分页插件的Count();函数中并没有插入租户。于是我检查了我的代码,发现在我的配置类中,先将分页插件注册到拦截其中,再将租户插件注册到拦截器中,我就在想,将他们的注册顺序调换一下就是不是就可以了,没想到还真是这样。
//错误的配置顺序:先配置了分页,再配置租户,这样配置的后果就是page.getTotal();的数值和实际数值不符。
/**
* 插件配置
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//注册分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
if (tenantProperties.getEnable()) {
//注册租户插件
interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(customTenantHandler));
}
}
//正确的配置顺序,先配置租户过滤器,再配置分页过滤器,前文贴出的代码按照此顺序配置
/**
* 插件配置
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
if (tenantProperties.getEnable()) {
//注册租户插件
interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(customTenantHandler));
}
//注册分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}