Sharding-JDBC学习

特点

  • 一个实现了JDBC API的jar包
  • 客户端直连数据库,没有中间层
  • 支持同时分表分库
  • 读写分离
  • 分布式主键
  • 最终一致性事务(最大努力送达型)
  • 多种配置方式:java, YAML, XML, Spring Boot Starter
  • 分片配置集中化,动态化

核心概念

  • LogicTable  数据分片的逻辑表,对于水平拆分的数据库(表),同一类表的总称。例:订单数据根据主键尾数拆分为10张表,分别是t_order_0到t_order_9,他们的逻辑表名为t_order。
  • ActualTable  在分片的数据库中真实存在的物理表。即上个示例中的t_order_0到t_order_9。
  • DataNode  数据分片的最小单元。由数据源名称和数据表组成,例:ds_1.t_order_0。配置时默认各个分片数据库的表结构均相同,直接配置逻辑表和真实表对应关系即可。如果各数据库的表结果不同,可使用ds.actual_table配置。
  • BindingTable  指在任何场景下分片规则均一致的主表和子表。例:订单表和订单项表,均按照订单ID分片,则此两张表互为BindingTable关系。BindingTable关系的多表关联查询不会出现笛卡尔积关联,关联查询效率将大大提升。
  • ShardingColumn  分片字段。用于将数据库(表)水平拆分的关键字段。例:订单表订单ID分片尾数取模分片,则订单ID为分片字段。SQL中如果无分片字段,将执行全路由,性能较差。Sharding-JDBC支持多分片字段。

整体架构

 

分片规则配置

ds_0
  ├── user_0
  ├── user_1
  ├── order_0
  ├── order_1

ds_1
  ├── user_2
  ├── user_3
  ├── order_2
  ├── order_3

分库键: user.id, order.user_id

分表键: user.id, order.user_id

分库算法: ${分片键} % 4 / 2

分表算法: ${分片键} % 4

 

SQL路由

CaseLogic SQL:

Actual SQL:

没有指定分片键select * from user

ds_0 ::: select * from user_0

ds_0 ::: select * from user_1

ds_1 ::: select * from user_2

ds_1 ::: select * from user_3

指定分片键select * from user where id = 1ds_0 ::: select * from user_1 where id = 1
绑定表joinselect * from user, order where user.id = order.user_id

ds_0 ::: select * from user_0, order_0 where user_0.id = order_0.user_id

ds_0 ::: select * from user_1, order_1 where user_1.id = order_1.user_id

ds_1 ::: select * from user_2, order_2 where user_2.id = order_2.user_id

ds_1 ::: select * from user_3, order_3 where user_3.id = order_3.user_id

自动生成id作为分片键insert into user(username, password, channel) values('terry', '123456', 'OFFLINE')ds_0 ::: insert into user_1(username, password, channel, id) values('terry', '123456', 'OFFLINE', 5595064747165309)

 

SQL改写

CaseLogic SQL:

Actual SQL:

换表名select * from user where id = 1ds_0 ::: select * from user_1 where id = 1
自动生成分布式主键insert into user(username, password, channel) values('terry', '123456', 'OFFLINE')

ds_0 ::: insert into user_1(username, password, channel, id) values('terry', '123456', 'OFFLINE', 5595064747165309)

翻页select * from order order by amount limit 100, 10 

ds_0 ::: select * from order_0 order by amount limit 0, 110

ds_0 ::: select * from order_1 order by amount limit 0, 110

ds_1 ::: select * from order_2 order by amount limit 0, 110

ds_1 ::: select * from order_3 order by amount limit 0, 110

聚合函数select avg(amount) from order

ds_0 ::: select avg(amount) , COUNT(amount) AS AVG_DERIVED_COUNT_0 , SUM(amount) AS AVG_DERIVED_SUM_0 from order_0

ds_0 ::: select avg(amount) , COUNT(amount) AS AVG_DERIVED_COUNT_0 , SUM(amount) AS AVG_DERIVED_SUM_0 from order_1

ds_1 ::: select avg(amount) , COUNT(amount) AS AVG_DERIVED_COUNT_0 , SUM(amount) AS AVG_DERIVED_SUM_0 from order_2

ds_1 ::: select avg(amount) , COUNT(amount) AS AVG_DERIVED_COUNT_0 , SUM(amount) AS AVG_DERIVED_SUM_0 from order_3

 

结果合并

order by sql的结果集合并使用归并排序算法, 一边遍历一边排序,无需放到内存中排序.

CaseLogic SQL:

合并算法

仅合并select * from usermerge(resultset1, resltset2, ..resultsetN)
order byselect * from user order by idsort(merge(resultset1, resltset2, ..resultsetN)
sum, countselect count(*) from usercount1 + count2 +.. countN
分组聚合select count(*), user_id from order group by user_id(count1 + count2 +.. countN) group by user_id
avgselect avg(amount) from order(sum1 + sum2 +.. sumN) / count1 + count2 +.. countN
max, minselect max(amount) from ordermax(max1, max2, ..maxN)
分页select * from order limit 100, 10merge(limit1(0, 110) + limit2(0, 110) + limitN(0,110)) -> limit(100, 10)

 

SQL执行

 

示例

        // 配置真实数据源
        Map<String, DataSource> dataSourceMap = new HashMap<>();

        // 配置第一个数据源
        BasicDataSource dataSource1 = new BasicDataSource();
        dataSource1.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource1.setUrl(jdbcurl + "mycat_demo00");
        dataSource1.setUsername(username);
        dataSource1.setPassword(password);
        dataSourceMap.put("ds_0", dataSource1);

        // 配置第二个数据源
        BasicDataSource dataSource2 = new BasicDataSource();
        dataSource2.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource2.setUrl(jdbcurl + "mycat_demo01");
        dataSource2.setUsername(username);
        dataSource2.setPassword(password);
        dataSourceMap.put("ds_1", dataSource2);

        // 配置表规则
        TableRuleConfiguration userTableRuleConfig = new TableRuleConfiguration();
        userTableRuleConfig.setLogicTable("user");
        userTableRuleConfig.setActualDataNodes("ds_0.user_${0..1}, ds_1.user_${2..3}");
        userTableRuleConfig.setKeyGeneratorColumnName("id");
        TableRuleConfiguration orderTableRuleConfig = new TableRuleConfiguration();
        orderTableRuleConfig.setLogicTable("order");
        orderTableRuleConfig.setActualDataNodes("ds_0.order_${0..1}, ds_1.order_${2..3}");
        orderTableRuleConfig.setKeyGeneratorColumnName("id");

        // 配置分库策略
        userTableRuleConfig.setDatabaseShardingStrategyConfig(new InlineShardingStrategyConfiguration("id", "ds_${(id % 4).intdiv(2)}"));
        orderTableRuleConfig.setDatabaseShardingStrategyConfig(new InlineShardingStrategyConfiguration("user_id", "ds_${(user_id % 4).intdiv(2)}"));

        // 配置分表策略
        userTableRuleConfig.setTableShardingStrategyConfig(new InlineShardingStrategyConfiguration("id", "user_${id % 4}"));
        orderTableRuleConfig.setTableShardingStrategyConfig(new InlineShardingStrategyConfiguration("user_id", "order_${user_id % 4}"));

        // 配置分片规则
        ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
        shardingRuleConfig.setDefaultKeyGeneratorClass("io.shardingjdbc.core.keygen.DefaultKeyGenerator");
        shardingRuleConfig.getTableRuleConfigs().add(userTableRuleConfig);
        shardingRuleConfig.getTableRuleConfigs().add(orderTableRuleConfig);
        shardingRuleConfig.getBindingTableGroups().add("user, order");

        // 获取数据源对象
        Properties properties = new Properties();
        properties.put("sql.show", "true");
        DataSource dataSource = ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfig, new ConcurrentHashMap(), properties);

 

转载于:https://my.oschina.net/fifadxj/blog/1607447

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值