Sharding-JDBC 分表操作不生效的解决方法
根据您提供的信息,有几个可能导致分表操作不生效的原因:
-
配置错误:请确保您的 sharding-jdbc 配置文件中的分表规则和分表策略配置正确,并且与代码中的分表规则和策略一致。
-
逻辑错误:请确保您的查询语句中使用了正确的分表键,并且查询的时间范围在分表规则的范围内。
-
数据源选择错误:请确保您的数据源选择正确,即在动态数据源配置中选择了正确的数据源。
-
分表算法错误:请确保您自定义的分表算法实现类中的逻辑正确,并且返回了正确的分表表名。
建议您按照上述步骤逐一检查,查找可能的错误原因。如果问题仍然存在,请提供更详细的错误信息和日志,以便更好地帮助您解决问题。
代码示例
yml 配置
shardingsphere:
# 是否启用sharding
enabled: true
props:
sql.show: true
datasource:
names: sharding
# 分库数据源
sharding:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://222.190.41.66:30001/lyg_vehicle?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8
username: root
password: aaX9AEx2Gu1M/8pM6EvC+qvtXX0D3i7XJ+9oPCU3rA1D/wNFlCcOgbmKcBlaImBnMv58Hw4Sq+tqG6IJREHjpQ==
# 分片规则
sharding:
tables:
# 表名
lyg_tsvol:
actual-data-nodes: sharding.lyg_tsvol$->{2023..2024}0$->{1..9},sharding.lyg_tsvol$->{2022..2024}1$->{0..2} # 相当于lyg_tsvol_202301->lyg_tsvol_202412
table-strategy: # 分表策略
standard: # 标准分表策略
sharding-column: createtime # 分表列名
preciseAlgorithmClassName: com.itssky.modules.common.core.config.MyPreciseShardingAlgorithm # 精准的分片算法
RangeShardingAlgorithm: com.itssky.modules.common.core.config.MyRangeShardingAlgorithm # 范围分片算法
# 表名
lyg_vehicle:
actual-data-nodes: sharding.lyg_vehicle_$->{2023..2024}0$->{1..9},ds.t_log_$->{2022..2024}1$->{0..2} # 相当于lyg_vehicle_202301->lyg_vehicle_202412
table-strategy: # 分表策略
standard: # 标准分表策略
sharding-column: createtime # 分表列名
preciseAlgorithmClassName: com.itssky.modules.common.core.config.MyPreciseShardingAlgorithm # 精准的分片算法
RangeShardingAlgorithm: com.itssky.modules.common.core.config.MyRangeShardingAlgorithm # 范围分片算法
分片规则
public class MyPreciseShardingAlgorithm implements PreciseShardingAlgorithm<Timestamp> {
private String tableNamePrefix;
public MyPreciseShardingAlgorithm(String tableNamePrefix) {
this.tableNamePrefix = tableNamePrefix;
}
@Override
public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Timestamp> shardingValue) {
// 获取年份和月份
Calendar calendar = Calendar.getInstance();
calendar.setTime(shardingValue.getValue());
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH) + 1;
// 构造表名
String tableName = tableNamePrefix + year + String.format('%02d', month);
// 如果这个表名存在于可用的目标表名中,那么返回这个表名
if (availableTargetNames.contains(tableName)) {
return tableName;
}
// 否则,抛出一个异常
throw new UnsupportedOperationException('未找到匹配的数据表: ' + tableName);
}
}
public class MyRangeShardingAlgorithm implements RangeShardingAlgorithm<Timestamp> {
@Override
public Collection<String> doSharding(Collection<String> collection,
RangeShardingValue<Timestamp> rangeShardingValue) {
Range<Timestamp> valueRange = rangeShardingValue.getValueRange();
Date lowerEnd = valueRange.lowerEndpoint();
Date upperEnd = valueRange.upperEndpoint();
log.info('范围分片开始时间:{},结束时间:{}',lowerEnd,upperEnd);
Set<String> routTables = new HashSet<>();
if (lowerEnd != null && upperEnd != null) {
List<String> rangeNameList = getTableNames(lowerEnd, upperEnd);
for (String string : rangeNameList) {
//这里的表名是逻辑表名+年月
routTables.add(rangeShardingValue.getLogicTableName() + string);
}
}
log.info('范围分片表名为:{}',routTables.toString());
return routTables;
}
/**
* 根据开始时间和结束时间获取表名
* @param start
* @param end
* @return
*/
private static List<String> getTableNames(Date start, Date end) {
List<String> result = Lists.newArrayList();
// 定义日期实例
Calendar calendar = Calendar.getInstance();
// 设置日期起始时间
calendar.setTime(start);
// 判断是否到结束日期
while (calendar.getTime().before(end)) {
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH) + 1; // Calendar.MONTH 是从0开始的,所以需要加1
String yearMonth = String.format('%d%02d', year, month); // 格式化为年月,例如202308或者202411
result.add(yearMonth);
// 进行当前日期月份加1
calendar.add(Calendar.MONTH, 1);
}
Calendar endCalendar = Calendar.getInstance();
endCalendar.setTime(end);
if (calendar.get(Calendar.MONTH)==endCalendar.get(Calendar.MONTH)){
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH) + 1;
String yearMonth = String.format('%d%02d', year, month);
result.add(yearMonth);
}
return result;
}
}
sharding_jdbc 配置信息
private TableRuleConfiguration createTableRule(String tableName) {
// 获取当前日期
LocalDate currentDate = LocalDate.now();
int currentYear = currentDate.getYear();
int currentMonth = currentDate.getMonthValue();
// 表规则配置
TableRuleConfiguration tableRuleConfig = new TableRuleConfiguration(tableName, tableName + '$->{2023..' + currentYear + '}0$->{6..' + currentMonth + '}');
// 配置分表策略
tableRuleConfig.setTableShardingStrategyConfig(new StandardShardingStrategyConfiguration('createtime', new MyPreciseShardingAlgorithm(tableName)));
// 分布式主键
tableRuleConfig.setKeyGeneratorConfig(new KeyGeneratorConfiguration('SNOWFLAKE', 'ID'));
return tableRuleConfig;
}
/**
* 系统参数配置
*/
private Properties getProperties() {
Properties shardingProperties = new Properties();
shardingProperties.put('sql.show', true);
return shardingProperties;
}
多数据源配置:DruidConfig
@Bean(name = 'dynamicDataSource')
@Primary
public DynamicDataSource dataSource(DataSource masterDataSource)
{
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);
setDataSource(targetDataSources, DataSourceType.SLAVE.name(), 'slaveDataSource');
setDataSource(targetDataSources, DataSourceType.SHARDING.name(), 'shardingDataSource');
return new DynamicDataSource(masterDataSource, targetDataSources);
}
问题排查
- 确保您的代码中使用了正确的分表键
createtime,并且查询的时间范围在分表规则的范围内。 - 确认您的数据源选择正确,即在动态数据源配置中选择了
shardingDataSource。 - 在
MyRangeShardingAlgorithm文件中打断点,观察是否能进入该算法,并检查算法逻辑是否正确。 - 查看您的 SQL 查询语句,确认是否使用了
lyg_tsvol逻辑表名,而不是具体的分表名。 - 检查
MyPreciseShardingAlgorithm和MyRangeShardingAlgorithm的实现类,确保逻辑正确,并且返回了正确的分表表名。
如果问题仍然存在,请提供更详细的错误信息和日志,以便更好地帮助您解决问题。
示例代码
// 插入数据
Timestamp currentTime = new Timestamp(System.currentTimeMillis());
LygTsvol tsvol = new LygTsvol();
tsvol.setCreatetime(currentTime);
// 使用 sharding-jdbc 的操作类进行插入
// ...
// 查询数据
// 使用 sharding-jdbc 的操作类进行查询
List<LygTsvol> tsvolList = // ...
// 获取所有分表名
Collection<String> tableNames = shardingRule.getTableRule(lyg_tsvol).getActualDataNodes();
// 打印所有分表名
System.out.println(tableNames);
// 查询指定时间范围的数据
Timestamp startTime = new Timestamp(System.currentTimeMillis() - 24 * 60 * 60 * 1000); // 昨天
Timestamp endTime = new Timestamp(System.currentTimeMillis()); // 今天
List<LygTsvol> tsvolList = // ...
总结
本文介绍了 sharding-jdbc 分表操作不生效的常见原因和解决方法,通过逐步排查,可以有效地解决分表问题。在实际应用中,还需要根据具体的业务场景进行调整和优化。
原文地址: https://www.cveoy.top/t/topic/qrym 著作权归作者所有。请勿转载和采集!