提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
SpringBoot 整合 Sharding-JDBC
提示:以下是本篇文章正文内容,下面案例可供参考
是轻量级的 java 框架,是增强版的 JDBC 驱动,就是简化分库分表后对数据相关操作
项目需求就是银行流水信息入mysql,水平按照流水时间分片分库分表
新建springboot项目引入下面依赖
按照水平分表的方式,创建数据库和数据库表
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-test
com.alibaba
druid-spring-boot-starter
1.1.20
mysql
mysql-connector-java
org.apache.shardingsphere
sharding-jdbc-spring-boot-starter
4.0.0-RC1
com.baomidou
mybatis-plus-boot-starter
3.0.5
org.projectlombok
lombok
CREATE TABLE `bank_flow_2021`.money_flow_202201 (
id INT(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
flow_id VARCHAR(50) NOT NULL COMMENT '流水id',
money DECIMAL(10,4) NOT NULL COMMENT '金额',
create_time TIMESTAMP COMMENT '创建时间',
flow_time TIMESTAMP NOT NULL COMMENT '流水时间',
sharding_time BIGINT(20) NOT NULL COMMENT '分片时间'
)
准备工作已经完成下面我们看下代码
首先我们需要修改配置文件,可以参考官网Spring Boot配置 :: ShardingSphere
# shardingjdbc 分片策略
# 配置数据源,给数据源起名称
spring.shardingsphere.datasource.names=bank2021,bank2022
# 一个实体类对应多张表,覆盖
spring.main.allow-bean-definition-overriding=true
#配置数据源具体内容,包含连接池,驱动,地址,用户名和密码
spring.shardingsphere.datasource.bank2021.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.bank2021.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.bank2021.jdbc-url=jdbc:mysql://127.0.0.1:3306/bank_flow_2021?autoReconnect=true&allowMultiQueries=true
spring.shardingsphere.datasource.bank2021.username=root
spring.shardingsphere.datasource.bank2021.password=123456
#配置数据源具体内容,包含连接池,驱动,地址,用户名和密码
spring.shardingsphere.datasource.bank2022.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.bank2022.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.bank2022.jdbc-url=jdbc:mysql://127.0.0.1:3306/bank_flow_2022?autoReconnect=true&allowMultiQueries=true
spring.shardingsphere.datasource.bank2022.username=root
spring.shardingsphere.datasource.bank2022.password=123456
#指定 money_flow 表分布情况,配置表在哪个数据库里面,表名称都是什么
spring.shardingsphere.sharding.tables.money_flow.actual-data-nodes=bank2021.money_flow_20210${1..9},bank2021.money_flow_20211${0..2},bank2022.money_flow_20220${1..9},bank2022.money_flow_20221${0..2}
#指定数据库 表分片策略 数据库和表都用这个字段分片
spring.shardingsphere.sharding.tables.money_flow.database-strategy.standard.sharding-column=sharding_time
spring.shardingsphere.sharding.tables.money_flow.table-strategy.standard.sharding-column=sharding_time
#数据库分片策略
spring.shardingsphere.sharding.tables.money_flow.database-strategy.standard.preciseAlgorithmClassName=com.example.demo.config.PreciseDatabaseShardingAlgorithm
spring.shardingsphere.sharding.tables.money_flow.database-strategy.standard.rangeAlgorithmClassName=com.example.demo.config.RangeDatabaseShardingAlgorithm
#数据表分片策略
spring.shardingsphere.sharding.tables.money_flow.table-strategy.standard.preciseAlgorithmClassName=com.example.demo.config.PreciseTableShardingAlgorithm
spring.shardingsphere.sharding.tables.money_flow.table-strategy.standard.rangeAlgorithmClassName=com.example.demo.config.RangeTableShardingAlgorithm
# 打开 sql 输出日志
spring.shardingsphere.props.sql.show=true
分片策略也就是通过分片字段怎么找的所需表,需要代码,数据库和表相关分片策略见下面代码
/**
* 库精确分片算法
*
*/
public class PreciseDatabaseShardingAlgorithm implements PreciseShardingAlgorithm {
/**
* 库精确分片算法
*
* @param availableTargetNames 所有配置的库列表
* @param shardingValue 分片值
* @return 所匹配库的结果
*/
@Override
public String doSharding(Collection availableTargetNames,
PreciseShardingValue shardingValue) {
// 分片键值
Long value = shardingValue.getValue();
// 库后缀
String yearStr = ShardingAlgorithmUtil.getYearByMillisecond(value);
if (value <= 0) {
throw new UnsupportedOperationException("preciseShardingValue is null");
}
for (String availableTargetName : availableTargetNames) {
if (availableTargetName.endsWith(yearStr)) {
return availableTargetName;
}
}
throw new UnsupportedOperationException();
}
}
/**
* 库范围分片算法
*
*/
public class RangeDatabaseShardingAlgorithm implements RangeShardingAlgorithm {
/**
* 库范围分片算法
*
* @param availableTargetNames 所有配置的库列表
* @param rangeShardingValue 分片值,也就是save_time_com的值,范围分片算法必须提供开始时间和结束时间
* @return 所匹配库的结果
*/
@Override
public Collection doSharding(Collection availableTargetNames,
RangeShardingValue rangeShardingValue) {
ArrayList result = new ArrayList<>();
Range range = rangeShardingValue.getValueRange();
// 起始年和结束年
int startYear = Integer.parseInt(ShardingAlgorithmUtil.getYearByMillisecond(range.lowerEndpoint()));
int endYear = Integer.parseInt(ShardingAlgorithmUtil.getYearByMillisecond(range.upperEndpoint()));
return startYear == endYear ? theSameYear(String.valueOf(startYear), availableTargetNames, result)
: differentYear(startYear, endYear, availableTargetNames, result);
}
/**
* 同一年,说明只需要一个库
*/
private Collection theSameYear(String startTime, Collection availableTargetNames,
ArrayList result) {
for (String availableTargetName : availableTargetNames) {
if (availableTargetName.endsWith(startTime))
result.add(availableTargetName);
}
return result;
}
/**
* 跨年
*/
private Collection differentYear(int startYear, int endYear, Collection availableTargetNames,
ArrayList result) {
for (String availableTargetName : availableTargetNames) {
for (int i = startYear; i <= endYear; i++) {
if (availableTargetName.endsWith(String.valueOf(i)))
result.add(availableTargetName);
}
}
return result;
}
}
/**
* 表精确分片算法
*/
public class PreciseTableShardingAlgorithm implements PreciseShardingAlgorithm {
/**
* 表精确分片算法
*
* @param availableTargetNames 所有配置的表列表,这里代表所匹配到库的所有表
* @param shardingValue 分片值
* @return 所匹配表的结果
*/
@Override
public String doSharding(Collection availableTargetNames,
PreciseShardingValue shardingValue) {
// 分片键值
long value = shardingValue.getValue();
if (value <= 0) {
throw new UnsupportedOperationException("preciseShardingValue is null");
}
String yearJoinMonthStr = ShardingAlgorithmUtil.getYearJoinMonthByMillisecond(value);
for (String availableTargetName : availableTargetNames) {
if (availableTargetName.endsWith(yearJoinMonthStr)) {
return availableTargetName;
}
}
throw new UnsupportedOperationException();
}
}
/**
* 表范围分片算法
*
*/
public class RangeTableShardingAlgorithm implements RangeShardingAlgorithm {
/**
* 表范围分片算法
*/
@Override
public Collection doSharding(Collection availableTargetNames,
RangeShardingValue rangeShardingValue) {
Range range = rangeShardingValue.getValueRange();
long startMillisecond = range.lowerEndpoint();
long endMillisecond = range.upperEndpoint();
return getMonthBetween(startMillisecond, endMillisecond, availableTargetNames);
}
/**
* 计算有效的库表名
*/
public static Collection getMonthBetween(long minTime, long maxTime,
Collection availableTargetNames) {
Collection result = new ArrayList<>();
Calendar min = Calendar.getInstance();
Calendar max = Calendar.getInstance();
min.setTime(new Date(minTime));
min.set(min.get(Calendar.YEAR), min.get(Calendar.MONTH), 1);
max.setTime(new Date(maxTime));
max.set(max.get(Calendar.YEAR), max.get(Calendar.MONTH), 2);
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM");
while (min.before(max)) {
String yyyyMM = sdf.format(min.getTime());
availableTargetNames.forEach(availableTargetName -> {
if (availableTargetName.endsWith(yyyyMM)) {
result.add(availableTargetName);
}
});
min.add(Calendar.MONTH, 1);
}
return result;
}
}
/**
* 分片算法工具类
*/
public class ShardingAlgorithmUtil {
/**
* 获取年份
*/
public static String getYearByMillisecond(long millisecond) {
return new SimpleDateFormat("yyyy").format(new Date(millisecond));
}
/**
* 获取年月
*/
public static String getYearJoinMonthByMillisecond(long millisecond) {
return new SimpleDateFormat("yyyyMM").format(new Date(millisecond));
}
}
新建实体类
@Data
@TableName(value = "money_flow")
public class BankFlow {
private Long id;
private String flowId;
private BigDecimal money;
private Instant flowTime;
private Instant createTime;
private Long shardingTime;
}
新建mapper
@Repository
public interface BankFlowMapper extends BaseMapper {
}
代码测试下
@SpringBootTest
class DemoApplicationTests {
@Autowired
private BankFlowMapper bankFlowMapper;
@Test
void saveFlow() {
BankFlow bankFlow = new BankFlow();
bankFlow.setId(100L);
bankFlow.setCreateTime(Instant.now());
bankFlow.setFlowTime(Instant.now());
bankFlow.setFlowId("ceshi");
bankFlow.setMoney(new BigDecimal("888.88"));
bankFlow.setShardingTime(new Date().getTime());
bankFlowMapper.insert(bankFlow);
}
}
数据已经进入相关的库表里面了
以上就是今天要讲的内容,范围的分片之前查询的时候使用分片字段使用between..and ..就可以了