合规国际互联网加速 OSASE为企业客户提供高速稳定SD-WAN国际加速解决方案。 广告
## 每个租户一个表 参考代码在源码 [S6MoreDatabase.multipleTables](https://gitee.com/xiandafu/beetlsql/blob/master/sql-samples/sql-sample-quickstart/src/main/java/org/beetl/sql/test/S6MoreDatabase.java) 可以为每个租户设置一个表。BeetlSQL为了实现此特性,需要较为复杂的操作。首先,在@Table 或者 sql模板中指定表名的时候使用动态表名 ```java static final String USER_TABLE="${toTable('sys_user')}"; @Data @Table(name = USER_TABLE) public class MyUser { @AssignID private Integer id; private String name; } ``` 我们的表名使用了`${toTable('sys_user')}` ,toTable是待会需要定义的一个函数名,输入是sys_user,输出可能是以tenant为后缀的表名,比如sys_user_beijing,sys_user_chengdu 为了使得BeetlSQL能识别动态表明${toTable('sys_user')},还需要配置SQLManager ```java protected SQLManager getSQLManager4MultipleTables(){ SQLManager sqlManager = SampleHelper.getSqlManager(); //告诉sqlManager遇到${toTable('sys_user')}这个不存在的表不报错,它是个虚表,真实表是sys_user,beetlsql用于获取表结构信息 sqlManager.addVirtualTable("sys_user",USER_TABLE); BeetlTemplateEngine templateEngine = (BeetlTemplateEngine)sqlManager.getSqlTemplateEngine(); // 注册一个方法来实现映射到多表的逻辑 templateEngine.getBeetl().getGroupTemplate().registerFunction("toTable", new Function(){ @Override public Object call(Object[] paras, Context ctx) { String tableName = (String)paras[0]; String tenantId = TenantLocalContext.get(); return tableName+"_"+tenantId } }); return sqlManager; } ``` * addVirtualTable ,接受俩个第一个参数,第一个是对应数据库的真实的表,第二个参数是也是一个表名,但不存在数据库,是个虚拟的表,当BeetlSQL需要知道虚拟表的metadata信息的时候,就从对应的真实表里查找。这常用分表环境中,比如数据库有bbs_topic_01到 bbs_topic_10, BeetSQL可以自定表名为@Table(name="bbs_topic"),但考虑系统并未有bbs_topic表,所以可以addVirtualTable("bbs_topic_01","bbs_topic"), 以方便如果需要知道"bbs_topic“表的信息,可以从bbs_topic_01中找到。在如上的虚拟表是个函数`${toTable('sys_user')}` 对应的表信息可以从sys_user中获取 * BeetlSQL默认使用Beetl引擎,因此自定义了个toTable函数,会接受一个表名,然后根据上下文(TenantLocalContext)来取得当前租户信息,代码如下 ```JAVA String tableName = (String)paras[0]; String tenantId = TenantLocalContext.get(); return tableName+"_"+tenantId ``` 有了如上配置后,可以使用`${toTable('sys_user')}`代替当前表 ```java TenantLocalContext.set(teantId); sqlManger.insert(MyUser.class); String sql = "select * from ${toTable('sys_user')} where department_id=#{xxx}"; List<TenantUser> list = sqlManager.execute(sql,TenantUser.class,new HashMap()); ``` 如果你熟悉jsqlparser工具,也可以通过Intecetpor功能(例子可以参考源码samples工程中的InterceptSample),在即将执行sql语句的前,改写sql语句 ```java public static class TenantUpdateAppendInterceptor implements Interceptor{ @Override public void before(InterceptorContext ctx) { String jdbcSql = context.sqlResult.jdbcSql; String newSql = parseTeantSql(jdbcSql) //解析sql语句,换成租户表 context.sqlResult.jdbcSql = newSql } } ```