多租户 SQL 解析器

  • 这里配合 分页拦截器 使用, spring boot 例子配置如下:

示例工程:

👉 mybatis-plus-sample-tenant多租户 SQL 解析器 - 图1

👉 mybatisplus-spring-boot多租户 SQL 解析器 - 图2

  1. @Bean
  2. public PaginationInterceptor paginationInterceptor() {
  3. PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
  4. /*
  5. * 【测试多租户】 SQL 解析处理拦截器<br>
  6. * 这里固定写成住户 1 实际情况你可以从cookie读取,因此数据看不到 【 麻花藤 】 这条记录( 注意观察 SQL )<br>
  7. */
  8. List<ISqlParser> sqlParserList = new ArrayList<>();
  9. TenantSqlParser tenantSqlParser = new TenantSqlParser();
  10. tenantSqlParser.setTenantHandler(new TenantHandler() {
  11. @Override
  12. public Expression getTenantId(boolean where) {
  13. // 该 where 条件 3.2.0 版本开始添加的,用于分区是否为在 where 条件中使用
  14. // 如果是in/between之类的多个tenantId的情况,参考下方示例
  15. return new LongValue(1L);
  16. }
  17. @Override
  18. public String getTenantIdColumn() {
  19. return "tenant_id";
  20. }
  21. @Override
  22. public boolean doTableFilter(String tableName) {
  23. // 这里可以判断是否过滤表
  24. /*
  25. if ("user".equals(tableName)) {
  26. return true;
  27. }*/
  28. return false;
  29. }
  30. });
  31. sqlParserList.add(tenantSqlParser);
  32. paginationInterceptor.setSqlParserList(sqlParserList);
  33. paginationInterceptor.setSqlParserFilter(new ISqlParserFilter() {
  34. @Override
  35. public boolean doFilter(MetaObject metaObject) {
  36. MappedStatement ms = SqlParserHelper.getMappedStatement(metaObject);
  37. // 过滤自定义查询此时无租户信息约束【 麻花藤 】出现
  38. if ("com.baomidou.springboot.mapper.UserMapper.selectListBySQL".equals(ms.getId())) {
  39. return true;
  40. }
  41. return false;
  42. }
  43. });
  44. return paginationInterceptor;
  45. }
  • 关于多租户实现条件tenant_id in (1,2,3)的解决方案

核心代码: MybatisPlusConfig

  1. /**
  2. * 2019-8-1
  3. *
  4. * https://gitee.com/baomidou/mybatis-plus/issues/IZZ3M
  5. *
  6. * 参考示例:
  7. * https://gitee.com/baomidou/mybatis-plus-samples/tree/master/mybatis-plus-sample-tenant
  8. *
  9. * tenant_id in (1,2)
  10. *
  11. * @return
  12. */
  13. @Override
  14. public Expression getTenantId(boolean where) {
  15. //如果是where,可以追加多租户多个条件in,不是where的情况:比如当insert时,不能insert into user(name, tenant_id) values('test', tenant_id IN (1, 2));
  16. final boolean multipleTenantIds = true;//自己判断是单个tenantId还是需要多个id in(1,2,3)
  17. if (where && multipleTenantIds) {
  18. //演示如何实现tenant_id in (1,2)
  19. return multipleTenantIdCondition();
  20. } else {
  21. //演示:tenant_id=1
  22. return singleTenantIdCondition();
  23. }
  24. }
  25. private Expression singleTenantIdCondition() {
  26. return new LongValue(1);//ID自己想办法获取到
  27. }
  28. private Expression multipleTenantIdCondition() {
  29. final InExpression inExpression = new InExpression();
  30. inExpression.setLeftExpression(new Column(getTenantIdColumn()));
  31. final ExpressionList itemsList = new ExpressionList();
  32. final List<Expression> inValues = new ArrayList<>(2);
  33. inValues.add(new LongValue(1));//ID自己想办法获取到
  34. inValues.add(new LongValue(2));
  35. itemsList.setExpressions(inValues);
  36. inExpression.setRightItemsList(itemsList);
  37. return inExpression;
  38. }
  39. public class MyTenantParser extends TenantSqlParser {
  40. //目前这种情况比较小众,自己定制可以参考
  41. //参考 https://gitee.com/baomidou/mybatis-plus-samples/blob/master/mybatis-plus-sample-tenant/src/main/java/com/baomidou/mybatisplus/samples/tenant/config/MyTenantParser.java
  42. }
  • 相关 SQL 解析如多租户可通过 @SqlParser(filter=true) 排除 SQL 解析,注意!!全局配置 sqlParserCache 设置为 true 才生效。(3.1.1开始不再需要这一步)
  1. # 开启 SQL 解析缓存注解生效
  2. mybatis-plus:
  3. global-config:
  4. sql-parser-cache: true