文章
问答
冒泡
Mybatis-plus 租户插件使用

Mybatis-plus提供了TenantLineInnerInterceptor全局租户插件,提供了租户数据隔离,刚好最近一个老项目面临多租户改造,老项目代码冗余多,不可控性高,所以多租户我打算采用逻辑隔离+租户插件的方式来做.

 

1、配置

1.1 自定义多租户策略配置

多租户插件的开启非常简单,自己实现mybatis-plus的 plugins包下的tenantLineHandler接口,接口提供

1,getTenantId()    获取租户 ID 值表达式,只支持单个 ID 值

2,getTenantIdColumn() 获取租户字段名

3,ignoreTable()    根据表名判断是否忽略拼接多租户条件

4,ingoreInsert()   忽略插入租户字段逻辑

四个方法,实现这四个方法并提供相应的返回值即可自定义租户策略.其中,getTenantId()方法需要提供获取当前线程租户Id的方法,getTenantIdColumn方法需要提供全局租户ID字段名称,ignoreTable 可以自定义不需要开启多租户的表名,我这里反向配置了需要开启多租户的表名,根据实际情况配置即可.

 

public class MyTenantLineHandler implements TenantLineHandler {

    private static List<String> tables = Lists.newArrayList(
            "sys_user"
    );

    @Override
    public Expression getTenantId() {
        Long tenantId = UserUtil.getTenantId();
        return tenantId == null ? new LongValue(1) : new LongValue(tenantId);
    }

    @Override
    public String getTenantIdColumn() {
        return "tenant_id";
    }

    @Override
    public boolean ignoreTable(String tableName) {
        return !tables.contains(tableName);
        // return TenantLineHandler.super.ignoreTable(tableName);
    }
}

2、将插件配置到mybatis-plus中

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new TenantLineInnerInterceptor(new MyTenantLineHandler()));
        return mybatisPlusInterceptor;
    }

3、开启mybatis-plus插件

MybatisSqlSessionFactoryBean factoryBean = new MybatisSqlSessionFactoryBean();
factoryBean.setPlugins(new Interceptor[]{mybatisPlusInterceptor,new PageInterceptor()});

4、调试

4.1 单元测试(插入)

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@Rollback
class SysUserServiceTest extends BaseTest {

    @Autowired
    private SysUserMapper sysUserMapper;
    @Test
    void add() {
        SysUserEntity sysUserEntity  = new SysUserEntity();
        sysUserEntity.setName("test1");
        sysUserEntity.setUsername("test1");
        sysUserEntity.setPassword("test1");
        sysUserMapper.insert(sysUserEntity);
    }
}

结果: 由于这里这里使用的是单元测试,所以userUtils获取的userInfo是空,所以走了默认的租户 = 1 的逻辑.这里可以看到插入的时候租户字段已经被拼接上了.

4.2 单元测试(查询)

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@Rollback
class SysUserServiceTest extends BaseTest {

    @Autowired
    private SysUserMapper sysUserMapper;

    @Test
    void detail() {
        SysUserEntity sysUserEntity = sysUserMapper.selectById(22);
    }
}

结果同上,也自动拼接上了租户条件

4.2 单元测试(删除)

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@Rollback
class SysUserServiceTest  {

    @Autowired
    private SysUserMapper sysUserMapper;

    @Test
    void delete() {
        sysUserMapper.deleteById(22);
    }
}

结果一致,这里我配置了逻辑删除,所以删除实际执行的是更新语句

5、其他配置

5.1 如果我们想要某个表被多租户插件管理,但是某个自定义sql语句不被多租户插件管理,则需要在sql上加上 @InterceptorIgnore(tenantLine = "true") 注解,这个注解是mybatis-plus提供的,内置了许多插件的开关,这里我们将tenantLine插件关掉.

    @InterceptorIgnore(tenantLine = "true")
    @Select("select * from sys_user where id = 22")
    SysUserEntity selectById(@Param("id") Long id);

5.2 这样调用的时候这条sql就不会被多租户插件管控了.

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@Rollback
class SysUserServiceTest extends BaseTest {

    @Autowired
    private SysUserMapper sysUserMapper;


    @Test
    void ignoreTenant(){
        sysUserMapper.selectById(22);
    }
}

结论,mybatis-plus的多租户插件在某些老项目多租户改造,同源同架构多租户方案上,还是有一定的使用便利性的.但是注意,同样为mybatis-plus的插件 InsertBatchSomeColumn批量插入插件下,却对多租户插件无效,并且插入数据时,如果提前设置了entity中的租户字段的值,那么多租户插件也会直接不生效.

Mybatis-plus
多租户

关于作者

Dane.shang
快30岁了还没去过酒吧
获得点赞
文章被阅读