目标
- 默认情况下,租户是使用tentid,实现表内隔离
- 租户可以选择独立数据库,独立文件系统。
ZLT多租户实现方案
概要
ZLT使用的实际是Mybatis-Plus的多租户方案。
注意其中关键的两个类,
TenantSqlParser TenantHandler
其中TenantSqlParser 需要一个 TenantHandler 接口成员,
根据TenantHandler 接口的
getTenantId()
getTenantIdColumn()
doTableFilter(String tableName)
三个方法分别配置租户ID的获取,租户ID的字段名,以及是否过滤该表
实现代码
实际上就是设置tentid,Mybatis-Plus会自动插入脚本,在crud层面自动处理了tentId
public class TenantContextHolder {
/**
* 支持父子线程之间的数据传递
*/
private static final ThreadLocal<String> CONTEXT = new TransmittableThreadLocal<>();
public static void setTenant(String tenant) {
CONTEXT.set(tenant);
}
public static String getTenant() { return CONTEXT.get(); }
public static void clear() {
CONTEXT.remove();
}
}
自动化配置,这个代码是丢在启动器里面的
@EnableConfigurationProperties(TenantProperties.class)
public class TenantAutoConfigure {
@Autowired
private TenantProperties tenantProperties;
@Bean
public TenantHandler tenantHandler() {
return new TenantHandler() {
/**
* 获取租户id
*/
@Override
public Expression getTenantId(boolean where) {
String tenant = TenantContextHolder.getTenant();
if (tenant != null) {
return new StringValue(TenantContextHolder.getTenant());
}
return new NullValue();
}
/**
* 获取租户列名
*/
@Override
public String getTenantIdColumn() {
return "tenant_id";
}
/**
* 过滤不需要根据租户隔离的表
* @param tableName 表名
*/
@Override
public boolean doTableFilter(String tableName) {
return tenantProperties.getIgnoreTables().stream().anyMatch(
(e) -> e.equalsIgnoreCase(tableName)
);
}
};
}
/**
* 过滤不需要根据租户隔离的MappedStatement
*/
@Bean
public ISqlParserFilter sqlParserFilter() {
return metaObject -> {
MappedStatement ms = SqlParserHelper.getMappedStatement(metaObject);
return tenantProperties.getIgnoreSqls().stream().anyMatch(
(e) -> e.equalsIgnoreCase(ms.getId())
);
};
}
}
代码增强:实现对多租户信息的获取
重写mybatis-plus里面的MultiTenantSqlParser的代码,这是对接口AbstractJsqlParser的实现。
protected Expression builderExpression(Expression currentExpression, Table table) {
Expression tenantExpression = this.tenantHandler.getTenantId(false);
Object appendExpression;
// 多个tenant id的情况
if (tenantExpression instanceof MultiOrExpression){
appendExpression = tenantExpression;
}else if (!(tenantExpression instanceof SupportsOldOracleJoinSyntax)) {
.....
}