问题遇到的现象和发生背景
最近在使用 sharding-jdbc 做分库分表是遇到的问题,默认分库策略【default-database-strategy】要如何配置才能对所有表都生效
业务上是多租户的类型的项目,每个表都存在一个 租户id 【tenant_id】, 通过mybatis plus的sql拦截器自动拼接在sql语句最后。
默认的分库策略是对于 tenant_id 做取模运算,路由到不同的数据库中。
我预期的结果是 对于未单独配置策略的 表,可以走 默认的分库策略 【default-database-strategy】,而实际上并未生效
我关于 sharding-jdbc 的配置如下:
shardingsphere:
props:
sql:
show: true
datasource:
# 数据源
names: master-0,slave-0,master-1,slave-1
# 配置master 数据源
master-0:
# 配置druid数据源
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://mysql-server:3307/xxx-0?&serverTimezone=GMT%2b8&useSSL=false
username: xxx
password: xxx
maxPoolSize: 100
minPoolSize: 5
slave-0:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://mysql-server:3307/xxx-0?&serverTimezone=GMT%2b8&useSSL=false
username: jadows-0
password: xxx
maxPoolSize: xxx
minPoolSize: 5
master-1:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://mysql-server:3307/xxx-1?&serverTimezone=GMT%2b8&useSSL=false
username: xxx
password: xxx
maxPoolSize: 100
minPoolSize: 5
slave-1:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://mysql-server:3307/xxx-1?&serverTimezone=GMT%2b8&useSSL=false
username: xxx
password: xxx
maxPoolSize: 100
minPoolSize: 5
sharding:
default-database-strategy:
inline:
sharding-column: tenant_id
algorithm-expression: master-$->{tenant_id % 2}
default-table-strategy:
none:
tables:
# login_record 逻辑表
login_record:
# 数据节点:数据源$->{0..N}.逻辑表名$->{0..N}
actual-data-nodes: master-$->{0..1}.login_record_$->{0..2}
# 拆分库策略
database-strategy:
inline:
# 分片字段
sharding-column: tenant_id
algorithm-expression: master-$->{tenant_id % 2}
# 拆分表策略
table-strategy:
inline:
# 分片字段(分片键)
sharding-column: id
# 分片算法表达式
algorithm-expression: login_record_$->{ id % 3 }
broadcast-tables:
- tenant
# 读写分离配置
master-slave-rules:
master-0:
master-data-source-name: master-0
slave-data-source-names: slave-0
master-1:
master-data-source-name: master-1
slave-data-source-names: slave-1
情况1) 未配置 user 表的 分表策略,查询 user 表
@Test
public void test() {
List<User> list = userService.list();
System.out.println(list);
List<User> l2 = userService.list();
System.out.println(l2);
}
执行上述两个查询,执行结果:
Actual SQL: slave-0 ::: SELECT id,..., created, tenant_id FROM `user` WHERE `user`.tenant_id = 0
Actual SQL: slave-1 ::: SELECT id,..., created, tenant_id FROM `user` WHERE `user`.tenant_id = 0
可以看到 ,master-slave 的策略生效,两次查询分别命中 slave-0 库 和 slave-1 库,而 default-database-stragegy 策略没有生效 【 预期:默认分库策略根据 tenant_id 取模,tenant_id 为 0 时 路由至 master-0 库,再根据 master-0 配置的的读写分离策略,两次查询都应该命中 slave-0 库】
情况2) 配置了 login_record 表的分表策略,查询 login_record 表
login_record 不按照 tenant_id 做分库【 记录用户的登录信息,未登录下不知道 tenant_id,所以取id 做分库字段 】,login_record 分为三张表,分别是
login_record_0
login_record_1
login_record_2
@Test
public void loginRecordTest() {
List<LoginRecord> list = loginRecordService.list();
System.out.println(list);
// 配置了 tables 策略 ,正确执行
List<LoginRecord> list = loginRecordService.list();
System.out.println(list);
List<LoginRecord> list2 = loginRecordService.list();
System.out.println(list2);
List<LoginRecord> list3 = loginRecordService.list();
System.out.println(list3);
List<LoginRecord> list4 = loginRecordService.list();
System.out.println(list4);
}
执行结果:
Actual SQL: slave-0 ::: SELECT id, user_name, ... FROM login_record_0 WHERE login_record_0.tenant_id = 0
Actual SQL: slave-0 ::: SELECT id, user_name, ... FROM login_record_1 WHERE login_record_1.tenant_id = 0
Actual SQL: slave-0 ::: SELECT id, user_name,... FROM login_record_2 WHERE login_record_2.tenant_id = 0
单独配置 table-statagy 时,符合预期。所有查询只命中 slave-0 库。
sharding-jdbc 及 springboot 版本:
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.1.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.12.RELEASE</version>
</dependency>
问题
需要如何配置,才能使得 数据库中所有的表 都支持默认的分库策略?