那么,有的小伙伴可能要问了,在业务中并不是所有的查询都需要过滤租户条件啊,针对这种情况,有两种方式来进行处理。
1、如果整张表的所有SQL操作都不需要针对租户进行操作,那么就对表进行过滤,修改doTableFilter方法,添加表的名称:
@Override public boolean doTableFilter(String tableName) { List<String> IGNORE_TENANT_TABLES= Arrays.asList("dept"); return IGNORE_TENANT_TABLES.stream().anyMatch(e->e.equalsIgnoreCase(tableName)); }
这样,在dept表的所有查询都不进行过滤:
2、如果有一些特定的SQL语句不想被执行租户过滤,可以通过@SqlParser注解的形式开启,注意注解只能加在Mapper接口的方法上:
@SqlParser(filter = true) @Select("select * from user where name =#{name}") User selectUserByName(@Param(value="name") String name);
或在分页拦截器中指定需要过滤的方法:
@Bean public PaginationInterceptor paginationInterceptor() { PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); paginationInterceptor.setSqlParserFilter(metaObject->{ MappedStatement ms = SqlParserHelper.getMappedStatement(metaObject); // 对应Mapper、dao中的方法 if("com.cn.tenant.dao.UserMapper.selectUserByPhone".equals(ms.getId())){ return true; } return false; }); ... }
上面这两种方式实现的功能相同,但是如果需要过滤的SQL语句很多,那么第二种方式配置起来会比较麻烦,因此建议通过注解的方式进行过滤。
除此之外,还有一个比较容易踩的坑就是在复制Bean时,不要复制租户id字段,否则会导致SQL语句报错:
public void createSnapshot(Long userId){ User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getId, userId)); UserSnapshot userSnapshot=new UserSnapshot(); BeanUtil.copyProperties(user,userSnapshot); userSnapshotMapper.insert(userSnapshot); }
查看报错可以看出,本身Bean的租户字段不为空的情况下,SQL又自动添加一次租户查询条件,因此导致了报错:
我们可以修改复制Bean语句,手动忽略租户id字段,这里使用的是hutool的BeanUtil工具类,可以添加忽略字段。
BeanUtil.copyProperties(user,userSnapshot,"tenantId");
在忽略了租户id的拷贝后,查询可以正常执行。
最后,再来看一下对联表查询的支持,首先看一下包含子查询的SQL:
@Select("select * from user where id in (select id from user_snapshot)") List<User> selectSnapshot();
查看执行结果,可以看见,在子查询的内部也自动添加的租户查询条件:
再来看一下使用Join进行联表查询:
@Select("select u.* from user u left join user_snapshot us on u.id=us.id") List<User> selectSnapshot();
同样,会在左右两张表上都添加租户的过滤条件:
再看一下不使用Join的普通联表查询:
@Select("select u.* from user u ,user_snapshot us,dept d where u.id=us.id and d.id is not null") List<User> selectSnapshot();
查看执行结果,可以看见在这种情况下,只在FROM关键字后面的第一张表上添加了租户的过滤条件,因此如果使用这种查询方式,需要额外注意,用户需要手动在SQL语句中添加租户过滤。