经过 ShardingSphere分库分表查询 当中所介绍的 range 查询发现是报错的是不支持的,所以在本文当中主要就是介绍该问题的解决方案,就是自定义分片算法实现 range 查询,首先修改 application.properties 修改 db 与 table 的策略为我们自定义的策略如下:
分表策略:
spring.shardingsphere.rules.sharding.tables.t_order.table-strategy.standard.sharding-column=tid
spring.shardingsphere.rules.sharding.tables.t_order.table-strategy.standard.sharding-algorithm-name=standard-range-table
spring.shardingsphere.rules.sharding.sharding-algorithms.standard-range-table.type=STANDARD_TEST_TAB
分库策略:
spring.shardingsphere.rules.sharding.tables.t_order.database-strategy.standard.sharding-column=tid
spring.shardingsphere.rules.sharding.tables.t_order.database-strategy.standard.sharding-algorithm-name=standard-range-db
spring.shardingsphere.rules.sharding.sharding-algorithms.standard-range-db.type=STANDARD_TEST_DB
然后在我们项目结构当中新建一个包(algorithm),来存放我们自定义实现分片算法的代码,创建两个类 TableStandardAlgorithm.java, DbStandardAlgorithm.java 两个都需要实现一个 StandardShardingAlgorithm
接口,然后覆盖接口的方法, 一个是表的分片算法策略,一个是库的分片算法策略以类的开头名称进行区分:
TableStandardAlgorithm.java
/**
* @author BNTang
* @date 2021/12/13
*/
public class TableStandardAlgorithm implements StandardShardingAlgorithm<Long> {
/**
* @param tableNames 所有真实表的名称
* @param shardingValue 条件值
* @return {@link String}
*/
public String doSharding(Collection<String> tableNames, PreciseShardingValue<Long> shardingValue) {
String truthTable = shardingValue.getLogicTableName() + "_"
+ BigInteger.valueOf(shardingValue.getValue())
.mod(new BigInteger("2"));
if (tableNames.contains(truthTable)) {
return truthTable;
}
throw new UnsupportedOperationException("配置错误,表不存在");
}
/**
* 返回值是一个集合. 这个集合决定了范围查询时 要查询的表有哪些
*
* @param collection 集合
* @param rangeShardingValue 分片值范围
* @return {@link Collection}<{@link String}>
*/
public Collection<String> doSharding(Collection<String> collection, RangeShardingValue<Long> rangeShardingValue) {
String logicTableName = rangeShardingValue.getLogicTableName();
return Arrays.asList(logicTableName + "_0", logicTableName + "_1");
}
public void init() {
}
public String getType() {
return "STANDARD_TEST_TBL";
}
}
- doSharding,@return {@link String}:当中主要是逻辑就是根据
shardingValue.getValue()
获取到传入的条件值也就是 properties 当中配置的 tid,然后拿着该值进行模以 2 得到一个数,然后在通过shardingValue.getLogicTableName()
拿到逻辑表拼接计算出的值可得到真实表的名称,然后在判断一下有没有在tableNames
当中包含如果包含就返回拼接的表名称即可,如果不包含就抛了一个异常,不支持操作的异常 - doSharding @return {@link Collection}<{@link String}>:略
- init:略
- getType @return {@link String}:该方法就返回一个之前在 properties 当中所配置的 type
DbStandardAlgorithm.java
/**
* @author BNTang
* @date 2021/12/13
*/
public class DbStandardAlgorithm implements StandardShardingAlgorithm<Long> {
public String doSharding(Collection<String> collection, PreciseShardingValue<Long> shardingValue) {
for (String each : collection) {
if (each.endsWith(String.valueOf(shardingValue.getValue() % 2))) {
return each;
}
}
throw new UnsupportedOperationException("配置错误,库不存在");
}
public Collection<String> doSharding(Collection<String> collection, RangeShardingValue<Long> rangeShardingValue) {
return Arrays.asList("ds0", "ds1");
}
public void init() {
}
public String getType() {
return "STANDARD_TEST_DB";
}
}
如上分库的覆盖方法的含义自行参考如上分表的解释即可。运行查询,首先我们先不运行范围查询的,先来看看单个的,运行之后发现报错了:
大致的含义就是说我们没有实现一个 class 来自定义 SPI,关于什么是 SPI 我会在下一章节当中进行介绍也就是说还需要在新建关于实现 SPI 相关的配置类,本文就先只介绍自定义分库分表的策略即可。