ShardingSphere-JDBC 在5.x版本移除了默认数据源配置, 那在项目中大多不需要分片的表, 怎么办?看看官方怎么说
github上也有issues
看了半天,很遗憾, 没有看到满意的解决方案
如果在项目里分了多个库,不需要分片的表我就想指定用一个数据源,怎么破?
low点的解决方案1每个表都配置一下默认actualDataNode
server:
port: 8080
spring:
application:
name: sharding-jdbc
autoconfigure:
exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/sharding-jdbc?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
username: root
password: root
main:
allow-bean-definition-overriding: true
jpa:
show-sql: false
hibernate:
ddl-auto: none
shardingsphere:
mode:
# 运行模式类型。可选配置:Memory(不需要下面repository持久化)、Standalone、Cluster
type: Memory
datasource:
names: ds_1,ds_2
ds_1:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
# 注意: 使用druid作为连接池,这里要改成 url
url: jdbc:mysql://192.168.32.110:3306/sharding-jdbc?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
username: root
password: root
ds_2:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.32.111:3306/sharding-jdbc?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
username: root
password: root
rules:
sharding:
tables:
# 5.0之后移除了默认数据源,如果在这里不指定不分片表的话,会由sharding内部自己找数据源
tbl_test1:
actual-data-nodes: ds_2.tbl_test1
tbl_test2:
actual-data-nodes: ds_2.tbl_test2
props:
sql-show: true
我项目里有100张表,只有两张表需要分片, 其他的表要配置98次, 是不是有点low?
low点的解决方案2那是不是可以完全基于API的方式使用sharding API的方式没有配置文件方式灵活,而且这样解决,正常的表还需把表名配置到配置文件中,还是有点low 既然上面那么麻烦,那是不是可以让系统自己去识别系统有多少张表, 已经在sharding中配置了哪些表,他们的差集就是就是不需要分片的表,把这些表的规则添加到Sharding的rule中,再指定我们自己想指定的默认数据源 想法有了之后,开始落地 很显然,sharding需要代理数据源才能解析sql, 在通过分片规则重新拼接sql再转发。RuleConfiguration下与分片规则相关的是AlgorithmProvidedShardingRuleConfiguration,如下 接下来就是重头戏了! sharding的自动配置类需要注入数据源,这些分片规则都是保存在它数据源里的!刚开始我还没意识到哪有问题,我禁了sharding的autoConfig类,自己弄了一个配置类,与它的内容一样,在构建数据源的时候,我在规则里添加那些不需要分片表的规则,与我配置的自定义数据库相绑定,然后规则放到数据源中。但是! 但是!问题来了 数据源都没创建,jpa EntityManager怎么能注入呢,它是要依赖数据源的! , 在创建数据源的时候又想用jpa EntityManager,这就是个伪命题! 思考了很久,终于还是想到了解决思路 既然不能互相矛盾,那肯定是要先让数据源创建出来的,在sharding的自动配置完成了之后,它为我们做的是将它的数据源放到了ioc,这样在上层ORM框架执行sql,会被它的数据源解析,分片,发送。那么我是不是可以在整个ioc初始化完之前,在sharding-datasource的bean生成之后、在我自己定义的EntityBeanUtil创建完之后,重新生成一下sharding的datasource, 此时我已经能拿到所有的表了,之前的sharing分片规则我也能拿到,最后再替换掉ioc里的 ShardingDatasource,问题就迎刃而解了 ShardingPostProcess 这个类注入到spring容器只是起到一个过桥的作用,仅仅是在他创建的方法里去实现我替换Sharding 数据源的操作 到此搞定, 改一下自定义默认的数据源名,就可以实现需求了
在构建Sharding的AlgorithmProvidedShardingRuleConfiguration#tables(Collection#自定义配置
sharding:
exclude:
# 不需要分片的表
tables: tbl_test1,tbl_test2
# 默认的数据源
default:
data-source-name: ds_2
@Value("${sharding.default.data-source-name}")
private String shardingDefaultDataSourceName;
@Value("${sharding.exclude.tables}")
private String shardingExcludeTables;
@Bean
public RuleConfiguration ruleConfiguration(){
AlgorithmProvidedShardingRuleConfiguration ruleConfiguration = new AlgorithmProvidedShardingRuleConfiguration();
String[] tables = shardingExcludeTables.split(",");
for (String table : tables) {
ruleConfiguration.getTables().add(new ShardingTableRuleConfiguration(table, shardingDefaultDataSourceName + "." + table));
}
// .... 省略需要分片的表配置
return ruleConfiguration;
}
本质上还是如解决方案2一样,向rule中添加不需要分片的表的规则,指定actualDataNode, 区别是不用自己去配置表,由系统来完成
先理解一下内部机制,从看源码开始,毋庸置疑从自动配置类读起
@Configuration
@ComponentScan("org.apache.shardingsphere.spring.boot.converter")
@EnableConfigurationProperties(SpringBootPropertiesConfiguration.class)
@ConditionalOnProperty(prefix = "spring.shardingsphere", name = "enabled", havingValue = "true", matchIfMissing = true)
@AutoConfigureBefore(DataSourceAutoConfiguration.class)
@RequiredArgsConstructor
public class ShardingSphereAutoConfiguration implements EnvironmentAware {
private String schemaName;
private final SpringBootPropertiesConfiguration props;
private final Map
> rules, final ObjectProvider
而自定义的分片规则就是tables里, Collection 如下
看明白了,来实现! 先获取系统中所有的表,借助jpa entityManager,可以拿到所有entity, 从而获取到所有的表名, InitializingBean 就不用多讲了, 再对Sharding的RuleConfigration后置处理一下,把不需要分片的表添加到rule中
@Component
public class EntityBeanUtil implements InitializingBean {
private static Map
public class ShardingPostProcess {
private final String defaultDatasourceName;
ShardingPostProcess(String defaultDatasourceName) {
this.defaultDatasourceName = defaultDatasourceName;
}
public void postProcess(RuleConfiguration rules) {
if (rules instanceof AlgorithmProvidedShardingRuleConfiguration) {
Collection
...... 此处省略尝试的配置
## 自定义配置默认数据源
sharding:
default:
datasource: ds_2
@Configuration
@ComponentScan("org.apache.shardingsphere.spring.boot.converter")
@EnableConfigurationProperties(SpringBootPropertiesConfiguration.class)
@AutoConfigureAfter(value = ShardingSphereAutoConfiguration.class)
@RequiredArgsConstructor
public class SharingConfig implements BeanFactoryAware, EnvironmentAware {
@Value("${sharding.default.datasource}")
private String defaultDatasourceName;
private String schemaName;
private final SpringBootPropertiesConfiguration props;
private final Map
结语
> rules, final ObjectProvider
测试环节就省略了,有兴趣实现一下还是很有意思的
项目地址 gitee
有问题欢迎留言交流



