sharding-jdbc默认是不支持在程序的运行过程中动态的创建表的,如果需要做到动态的按月分表,所有的表需要提前创建好哦, 比如,你可以把这两年的表全部建立好。或者另外写个程序,专门用来创建表,具体怎么做,你们自己选择,本文主要是讲,如果通过sharding-jdbc实现按月动态分表。
设置数据源的时候,给该表设置分表规则
java代码
Bean
public ShardingRule shardingRule(DataSourceRule dataSourceRule){
//具体分库分表策略
TableRule userTableRule = TableRule.builder("t_user")
.actualTables(Arrays.asList("t_user_00", "t_user_01"))
.tableShardingStrategy(new TableShardingStrategy("user_id", new ModuloTableShardingAlgorithm()))
.dataSourceRule(dataSourceRule)
.build();
TableRule stuTableRule = TableRule.builder("t_stu")
.actualTables(Arrays.asList("t_stu"))
.tableShardingStrategy(new TableShardingStrategy("id", new TestTableShardingAlgorithm()))
.dataSourceRule(dataSourceRule)
.build();
// 按月动态分表
TableRule orderTableRule = TableRule.builder("t_order").
tableShardingStrategy(new TableShardingStrategy("createTime",
new SingleKeyDynamicModuloTableShardingAlgorithm("t_order_"))).
dataSourceRule(dataSourceRule).dynamic(true).build();
//绑定表策略,在查询时会使用主表策略计算路由的数据源,因此需要约定绑定表策略的表的规则需要一致,可以一定程度提高效率
List bindingTableRules = new ArrayList();
// bindingTableRules.add(new BindingTableRule(Arrays.asList(userTableRule,stuTableRule)));
return ShardingRule.builder()
.dataSourceRule(dataSourceRule)
.tableRules(Arrays.asList(userTableRule,stuTableRule,orderTableRule))
.bindingTableRules(bindingTableRules)
.databaseShardingStrategy(new DatabaseShardingStrategy("id", new ModuloDatabaseShardingAlgorithm()))
.tableShardingStrategy(new TableShardingStrategy("user_id", new ModuloTableShardingAlgorithm()))
.build();
}
上面截图的代码,是我的一个小例子,动态分表主要看这一段代码
// 按月动态分表
TableRule orderTableRule = TableRule.builder("t_order").
tableShardingStrategy(new TableShardingStrategy("createTime",
new SingleKeyDynamicModuloTableShardingAlgorithm("t_order_"))).
dataSourceRule(dataSourceRule).dynamic(true).build();
逻辑表t_order , 通过createTime进行分表, 分片规则类为SingleKeyDynamicModuloTableShardingAlgorithm
PS : 这里有一个属性比较重要,dynamic设置为true表示动态分表,否则是无效的。
yaml方式
dataSource:
db0: !!org.apache.commons.dbcp.BasicDataSource
driverClassName: org.h2.Driver
url: jdbc:h2:mem:%s;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;MODE=MYSQL
username: sa
password:
maxActive: 100
db1: !!org.apache.commons.dbcp.BasicDataSource
driverClassName: org.h2.Driver
url: jdbc:h2:mem:%s;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;MODE=MYSQL
username: sa
password:
maxActive: 100
tables:
config:
dynamic: true
t_order:
dynamic: true
databaseStrategy: &db001
shardingColumns: order_id
algorithmClassName: com.dangdang.ddframe.rdb.sharding.config.yaml.algorithm.SingleAlgorithm
tableStrategy: &table001
shardingColumns: id
algorithmExpression: t_order_${id.longValue() % 2}
t_order_item:
dynamic: true
#绑定表中其余的表的策略与第一张表的策略相同
databaseStrategy: *db001
tableStrategy: *table001
#默认数据库分片策略
defaultDatabaseStrategy:
shardingColumns: order_id, user_id
algorithmExpression: t_order_${id.longValue() % 2}
defaultTableStrategy:
shardingColumns: id, order_id
algorithmClassName: com.dangdang.ddframe.rdb.sharding.config.yaml.algorithm.MultiAlgorithm
分片策略
@RequiredArgsConstructor
public final class SingleKeyDynamicModuloTableShardingAlgorithm implements SingleKeyTableShardingAlgorithm {
private final String tablePrefix;
@Override
public String doEqualSharding(final Collection availableTargetNames, final ShardingValue shardingValue) {
SimpleDateFormat formatter = new SimpleDateFormat("yyyyMM");
return tablePrefix +formatter.format(shardingValue.getValue());
}
@Override
public Collection doInSharding(final Collection availableTargetNames, final ShardingValue shardingValue) {
Collection result = new LinkedHashSet<>(shardingValue.getValues().size());
SimpleDateFormat formatter = new SimpleDateFormat("yyyyMM");
for (Date value : shardingValue.getValues()) {
result.add(tablePrefix + formatter.format(value));
}
return result;
}
@Override
public Collection doBetweenSharding(final Collection availableTargetNames, final ShardingValue shardingValue) {
Collection result = new LinkedHashSet<>();
DateFormat sdf = new SimpleDateFormat("yyyyMM");
Range ranges = shardingValue.getValueRange();
Date startTime = ranges.lowerEndpoint();
Date endTime = ranges.upperEndpoint();
// range.lowerEndpoint() = 2018-08-01
// range.upperEndpoint() = 2018-10-01
// 此处应该返回 tablePrefix+201808 , tablePrefix+201809,tablePrefix+201810,
Calendar cal = Calendar.getInstance();
while (startTime.getTime()<=endTime.getTime()){
result.add(tablePrefix + sdf.format(startTime));
cal.setTime(startTime);//设置起时间
cal.add(Calendar.MONTH,1);
startTime = cal.getTime();
}
return result;
}
}
是的,既然你按照日期来分表,这说明你每日产生的数据是非常大的,这种情况,一般来说,产品设计上,都是需要根据时间段来查询的,不然这样做分表的意义何在?
既然做了分表,那么查询条件里面一般都要包含分片键,动态分片的话是必须包含分片键的。 静态分片可以不用,但是那就会所有的库和表都会查一遍。
转载于:https://blog.csdn.net/u012394095/article/details/81705382