开启成长之旅!这是我参与「日新计划 12 月更文挑战」的第20天,点击检查活动概况
话不多说,直接开始。
一、引入依靠
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
<version>5.1.2</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
二、yml装备
包含数据源装备、数据节点装备、分片战略装备、主键生成战略等装备
server:
port: 9088
spring:
shardingsphere:
datasource:
names: ds0,ds1
ds0:
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/order?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
username: root
password: root
ds1:
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/shop?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
username: root
password: root
enabled: true
mode:
type: memory
props:
sql-show: true
rules:
sharding:
default-key-generate-strategy:
column: id
key-generators:
id-key:
type: SNOWFLAKE
tables:
# 需求分表的逻辑表名, 假如需求装备多个数据表,依照这个规矩装备就可以
test_data:
# 表的实在表列表(需求留意这儿的表都应该存在,不然就有可能出现我第一篇文章里边说到的 NPE 异常)
actual-data-nodes: ds0.test_data_20220${8..9}, ds0.test_data_2022${10..12}
# 分片战略装备
table-strategy:
standard:
# 分片算法是 his_month_sharding, 这个称号是在下面装备的
sharding-algorithm-name: his_month_sharding
# 分片列是 acquisition_time, 需求留意的是,分表算法的数据类型一定要和这个分片的列数据类型一致
sharding-column: create_time
# 装备分片算法
sharding-algorithms:
# 分片算法称号
his_month_sharding:
# 分片算法类型,这个type就是咱们的分片算法完成类中 getType() 的返回值,SPI适用于这种方法
type: HIS_DATA_SPI_BASED
三、完成分片算法
这儿首要标准分片算法接口,官方保留了接口,详细算法需求自己动手完成。通过分片键create_time完成规模查找和准确查找。
@Slf4j
public class TstDataMonthShardingAlgorithm implements StandardShardingAlgorithm<Date> {
private final ThreadLocal<SimpleDateFormat> formatThreadLocal = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyyMM"));
private Properties props;
/**
* 设置该参数的原因是,假如在规模查找的时分咱们没有设置最小值,比如下面的查询
* where acquisition_time < '2022-08-11 00:00:00'
* 这个时分规模查找就只有上限而没有下限,这时分就需求有一个下限值兜底,不能一致遍历下去
*/
private Date tableLowerDate;
/**
*
* @param availableTargetNames 可用的表列表(装备文件中装备的 actual-data-nodes会被解析成 列表被传递过来)
* @param shardingValue 准确的值
* @return
*/
@Override
public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Date> shardingValue) {
Date value = shardingValue.getValue();
// 依据准确值获取路由表
String actuallyTableName = shardingValue.getLogicTableName() + shardingSuffix(value);
if (availableTargetNames.contains(actuallyTableName)) {
return actuallyTableName;
}
return null;
}
@Override
public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Date> shardingValue) {
// 获取到规模查找的最小值,假如条件中没有最小值设置为 tableLowerDate
Date rangeLowerDate;
if (shardingValue.getValueRange().hasLowerBound()) {
rangeLowerDate = shardingValue.getValueRange().lowerEndpoint();
} else {
rangeLowerDate = tableLowerDate;
}
// 获取到规模查找的最大值,假如没有装备最大值,设置为当时时间 + 1 月
// 这儿需求留意,你的项目里边这样做是否合理
Date rangeUpperDate;
if (shardingValue.getValueRange().hasUpperBound()) {
rangeUpperDate = shardingValue.getValueRange().upperEndpoint();
} else {
// 往后延一个月
rangeUpperDate = DateUtil.offsetMonth(new Date(), 1);
}
rangeUpperDate = DateUtil.endOfMonth(rangeUpperDate);
List<String> tableNames = new ArrayList<>();
// 过滤那些存在的表
while (rangeLowerDate.before(rangeUpperDate)) {
String actuallyTableName = shardingValue.getLogicTableName() + shardingSuffix(rangeLowerDate);
if (availableTargetNames.contains(actuallyTableName)) {
tableNames.add(actuallyTableName);
}
rangeLowerDate = DateUtil.offsetMonth(rangeLowerDate, 1);
}
return tableNames;
}
/**
* sharding 表后缀 _yyyyMM
*/
private String shardingSuffix(Date shardingValue) {
return "_" + formatThreadLocal.get().format(shardingValue);
}
/**
* SPI方法的 SPI称号,装备文件中装备的时分需求用到
*/
@Override
public String getType() {
return "HIS_DATA_SPI_BASED";
}
@Override
public void init(Properties properties) {
this.props = properties;
String autoCreateTableLowerDate = properties.getProperty("auto-create-table-lower");
try {
this.tableLowerDate = formatThreadLocal.get().parse(autoCreateTableLowerDate);
} catch (Exception e) {
log.error("parse auto-create table lower date failed: {}, use default date 202208", e.getMessage());
try {
this.tableLowerDate = formatThreadLocal.get().parse("202208");
} catch (ParseException ignored) {
}
}
}
@Override
public Properties getProps() {
return this.props;
}
}
四、运用SPI注册服务
SPI全称Service Provider Interface,是Java供给的一套用来被第三方完成或者扩展的接口,它可以用来启用框架扩展和替换组件。SPI的效果就是为这些被扩展的API寻觅服务完成。
1、在resources目录下新建META-INF/services目录
-- resources
-- META-INF
-- services
2、在这个目录下新建一个与上述接口的全限定名一致的文件
3、在这个文件中写入接口的完成类的全限定名
五、操作测验
1、新增数据,依据createTime放入不同的表 { “name”:”8月5″, “createTime”:”2022-09-05 12:00:00″ }
2、依据ID=1600390521566187522查询数据
3、依据日期区间查询