场景:
sharding-jdbc动态更新分片规则
代码实现:
本实例采用的是通过类实现配置,需要数据源Map集合DataSourceMap、shrding-jdbc配置shardingConfig、定时执行更新节点逻辑ShardingTableRuleActualTablesRefreshSchedule
建立数据源Map集合的对应
@Configuration
public class DataSourceMapConfig {
@Value("${jdbcurl}")
private String url;
@Value("${name}")
private String username;
@Value("${password}")
private String password;
@Value("${driver-class-name}")
private String driverClassName;
private Map<String, DataSource> dsMap = new HashMap<>();
@PostConstruct
public void init(){
HikariDataSource hikariDataSource = new HikariDataSource();
hikariDataSource.setUsername(username);
hikariDataSource.setPassword(password);
hikariDataSource.setJdbcUrl(url);
hikariDataSource.setDriverClassName(driverClassName);
dsMap.put("m1", hikariDataSource);
}
public Map<String, DataSource> getDataSourceMap(){
return dsMap;
}
}
配置分片策略,并创建shardingDataSource
@Configuration
public class ShardingConfig {
@Autowired
private DataSourceMapConfig dataSourceMapConfig;
@Bean(name = "shardingDataSource")
public DataSource getShardingDataSource() throws SQLException {
ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
//分片表规则配置
shardingRuleConfig.getTableRuleConfigs().add(getOrderTableRuleConfiguration());
//设置默认表分片策略
//shardingRuleConfig.setDefaultTableShardingStrategyConfig(new StandardShardingStrategyConfiguration("order_id", new PreciseModuloShardingTableAlgorithm()));
//spring.shardingsphere.props.sql.show = true
Properties properties = new Properties(); properties.put("sql.show","true");
//创建ShardingDataSource数据源
return ShardingDataSourceFactory.createDataSource(dataSourceMapConfig.getDataSourceMap(), shardingRuleConfig, properties);
}
private TableRuleConfiguration getOrderTableRuleConfiguration() {
// 定义t_order表的分片策略
TableRuleConfiguration result = new TableRuleConfiguration("t_order","m1.t_order_${[1,2]}");
result.setTableShardingStrategyConfig(new StandardShardingStrategyConfiguration("order_id",new PreciseModuloShardingTableAlgorithm()));
result.setKeyGeneratorConfig(getKeyGeneratorConfiguration());
return result;
}
private KeyGeneratorConfiguration getKeyGeneratorConfiguration() {
//设置生成主键算法
KeyGeneratorConfiguration result = new KeyGeneratorConfiguration("SNOWFLAKE","order_id");
return result;
}
定时执行更新节点逻辑
@Slf4j
@Component
@EnableScheduling
@Order
public class ShardingTableRuleActualTablesRefreshSchedule implements InitializingBean {
private Logger logger = LoggerFactory.getLogger(ShardingTableRuleActualTablesRefreshSchedule.class);
@Resource(name = "shardingDataSource")
private DataSource dataSource;
@Scheduled(cron = "0/10 * * * * ?")
//刷新节点的逻辑,核心通过反射更新tableRule,
public void actualTablesRefresh() throws Exception {
logger.info("-----开始刷新表节点-----");
ShardingDataSource shardingDataSource = (ShardingDataSource)dataSource;
//运行时获取分片规则
ShardingRule rule = shardingDataSource.getRuntimeContext().getRule();
//获取分表策略集合
Collection<TableRule> tableRules = rule.getTableRules();
for (TableRule tableRule : tableRules) {
//获取真实节点
List<DataNode> actualDataNodes = tableRule.getActualDataNodes();
Field actualDataNodesField = TableRule.class.getDeclaredField("actualDataNodes");
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(actualDataNodesField, actualDataNodesField.getModifiers() & ~Modifier.FINAL);
//数据源名
String dataSourceName = actualDataNodes.get(0).getDataSourceName();
//逻辑表名
String logicTableName = tableRule.getLogicTable();
//根据真实业务,新增节点的逻辑
String tableName = actualDataNodes.get(actualDataNodes.size() - 1).getTableName();
int index = (int)(tableName.charAt(tableName.length()-1))+1-'0';
//新增节点
actualDataNodes.add(new DataNode(dataSourceName+"."+logicTableName+"_"+index));
actualDataNodesField.setAccessible(true);
actualDataNodesField.set(tableRule, actualDataNodes);
Set<String> actualTables = Sets.newHashSet();
Map<DataNode, Integer> dataNodeIntegerMap = Maps.newHashMap();
//更新actualTables、dataNodeIntegerMap
AtomicInteger a = new AtomicInteger(0);
actualDataNodes.forEach((dataNode -> {
actualTables.add(dataNode.getTableName());
if (a.intValue() == 0){
a.incrementAndGet();
dataNodeIntegerMap.put(dataNode, 0);
}else {
dataNodeIntegerMap.put(dataNode, a.intValue());
a.incrementAndGet();
}
}));
//动态刷新:actualTables
Field actualTablesField = TableRule.class.getDeclaredField("actualTables");
actualTablesField.setAccessible(true);
actualTablesField.set(tableRule, actualTables);
//动态刷新:dataNodeIndexMap
Field dataNodeIndexMapField = TableRule.class.getDeclaredField("dataNodeIndexMap");
dataNodeIndexMapField.setAccessible(true);
dataNodeIndexMapField.set(tableRule, dataNodeIntegerMap);
//动态刷新:datasourceToTablesMap
Map<String, Collection<String>> datasourceToTablesMap = Maps.newHashMap();
datasourceToTablesMap.put(dataSourceName, actualTables);
Field datasourceToTablesMapField = TableRule.class.getDeclaredField("datasourceToTablesMap");
datasourceToTablesMapField.setAccessible(true);
datasourceToTablesMapField.set(tableRule, datasourceToTablesMap);
logger.info("-----------------end----------------");
}
}
@Override
public void afterPropertiesSet() throws Exception{
actualTablesRefresh();
}