目标

  1. 默认情况下,租户是使用tentid,实现表内隔离
  2. 租户可以选择独立数据库,独立文件系统。

ZLT多租户实现方案

概要

ZLT使用的实际是Mybatis-Plus的多租户方案。

注意其中关键的两个类,
TenantSqlParser TenantHandler
其中TenantSqlParser 需要一个 TenantHandler 接口成员,

根据TenantHandler 接口的
getTenantId()
getTenantIdColumn()
doTableFilter(String tableName)
三个方法分别配置租户ID的获取,租户ID的字段名,以及是否过滤该表

ZLT的多租户机制及其增强 - 图1

实现代码

实际上就是设置tentid,Mybatis-Plus会自动插入脚本,在crud层面自动处理了tentId

  1. public class TenantContextHolder {
  2. /**
  3. * 支持父子线程之间的数据传递
  4. */
  5. private static final ThreadLocal<String> CONTEXT = new TransmittableThreadLocal<>();
  6. public static void setTenant(String tenant) {
  7. CONTEXT.set(tenant);
  8. }
  9. public static String getTenant() { return CONTEXT.get(); }
  10. public static void clear() {
  11. CONTEXT.remove();
  12. }
  13. }

自动化配置,这个代码是丢在启动器里面的

  1. @EnableConfigurationProperties(TenantProperties.class)
  2. public class TenantAutoConfigure {
  3. @Autowired
  4. private TenantProperties tenantProperties;
  5. @Bean
  6. public TenantHandler tenantHandler() {
  7. return new TenantHandler() {
  8. /**
  9. * 获取租户id
  10. */
  11. @Override
  12. public Expression getTenantId(boolean where) {
  13. String tenant = TenantContextHolder.getTenant();
  14. if (tenant != null) {
  15. return new StringValue(TenantContextHolder.getTenant());
  16. }
  17. return new NullValue();
  18. }
  19. /**
  20. * 获取租户列名
  21. */
  22. @Override
  23. public String getTenantIdColumn() {
  24. return "tenant_id";
  25. }
  26. /**
  27. * 过滤不需要根据租户隔离的表
  28. * @param tableName 表名
  29. */
  30. @Override
  31. public boolean doTableFilter(String tableName) {
  32. return tenantProperties.getIgnoreTables().stream().anyMatch(
  33. (e) -> e.equalsIgnoreCase(tableName)
  34. );
  35. }
  36. };
  37. }
  38. /**
  39. * 过滤不需要根据租户隔离的MappedStatement
  40. */
  41. @Bean
  42. public ISqlParserFilter sqlParserFilter() {
  43. return metaObject -> {
  44. MappedStatement ms = SqlParserHelper.getMappedStatement(metaObject);
  45. return tenantProperties.getIgnoreSqls().stream().anyMatch(
  46. (e) -> e.equalsIgnoreCase(ms.getId())
  47. );
  48. };
  49. }
  50. }

代码增强:实现对多租户信息的获取

重写mybatis-plus里面的MultiTenantSqlParser的代码,这是对接口AbstractJsqlParser的实现。

  1. protected Expression builderExpression(Expression currentExpression, Table table) {
  2. Expression tenantExpression = this.tenantHandler.getTenantId(false);
  3. Object appendExpression;
  4. // 多个tenant id的情况
  5. if (tenantExpression instanceof MultiOrExpression){
  6. appendExpression = tenantExpression;
  7. }else if (!(tenantExpression instanceof SupportsOldOracleJoinSyntax)) {
  8. .....
  9. }