sharding-jdbc之路由引擎

根据解析上下文匹配数据库和表的分片策略,并生成路由路径。 对于携带分片键的SQL,根据分片键的不同可以划分为单片路由(分片键的操作符是等号)、多片路由(分片键的操作符是IN)和范围路由(分片键的操作符是BETWEEN)。 不携带分片键的SQL则采用广播路由

分片策略通常可以采用由数据库内置或由用户方配置。 数据库内置的方案较为简单,内置的分片策略大致可分为尾数取模、哈希、范围、标签、时间等。 由用户方配置的分片策略则更加灵活,可以根据使用方需求定制复合分片策略。 如果配合数据自动迁移来使用,可以做到无需用户关注分片策略,自动由数据库中间层分片和平衡数据即可,进而做到使分布式数据库具有的弹性伸缩的能力。 在ShardingSphere的线路规划中,弹性伸缩将于4.x开启。

路由引擎的整体结构划分如下图
在这里插入图片描述

分片路由

分片路由又可分为直接路由、标准路由和笛卡尔积路由这3种类型。

直接路由

满足直接路由的条件相对苛刻,它需要通过Hint(使用HintAPI直接指定路由至库表)方式分片,并且是只分库不分表的前提下,则可以避免SQL解析和之后的结果归并。 因此它的兼容性最好,可以执行包括子查询、自定义函数等复杂情况的任意SQL。直接路由还可以用于分片键不在SQL中的场景。例如,设置用于数据库分片的键为3:

hintManager.setDatabaseShardingValue(3);

假如路由算法为value % 2,当一个逻辑库t_order对应2个真实库t_order_0和t_order_1时,路由后SQL将在t_order_1上执行。下方是使用API的代码样例:

String sql = "SELECT * FROM t_order";
try (
        HintManager hintManager = HintManager.getInstance();
        Connection conn = dataSource.getConnection();
        PreparedStatement pstmt = conn.prepareStatement(sql)) {
    hintManager.setDatabaseShardingValue(3);
    try (ResultSet rs = pstmt.executeQuery()) {
        while (rs.next()) {
            //...
        }
    }
}

直接路由源码:

@RequiredArgsConstructor
public final class DatabaseHintRoutingEngine implements RoutingEngine {
    //所有分库的数据库名称集合,由于直接路由只支持分库,不支持分表,不需要维护分表的集合
    private final Collection<String> dataSourceNames;
    //直接路由使用Hint路由策略进行分库
    private final HintShardingStrategy databaseShardingStrategy;
    
    @Override
    public RoutingResult route() {
    	 //获取数据库分片值
        Optional<ShardingValue> shardingValue = HintManagerHolder.getDatabaseShardingValue(HintManagerHolder.DB_TABLE_NAME);
        // 校验是否存在值
        Preconditions.checkState(shardingValue.isPresent());
        Collection<String> routingDataSources;
        //得到分片结果,Hint分片策略
        routingDataSources = databaseShardingStrategy.doSharding(dataSourceNames, Collections.singletonList(shardingValue.get()));
        Preconditions.checkState(!routingDataSources.isEmpty(), "no database route info");
        RoutingResult result = new RoutingResult();
        //遍历分片结果,填充到路由结果中
        for (String each : routingDataSources) {
        //路由表单元集合,主要存储数据库名和路由表(包含逻辑表和实际表名称)返回这个结果便于在下一步的改写中,指定数据库和实际表的sql
            result.getTableUnits().getTableUnits().add(new TableUnit(each));
        }
        return result;
    }
}

标准路由

标准路由是ShardingSphere最为推荐使用的分片方式,它的适用范围是不包含关联查询或仅包含绑定表之间关联查询的SQL。 当分片运算符是等于号时,路由结果将落入单库(表),当分片运算符是BETWEEN或IN时,则路由结果不一定落入唯一的库(表),因此一条逻辑SQL最终可能被拆分为多条用于执行的真实SQL。 举例说明,如果按照order_id的奇数和偶数进行数据分片,一个单表查询的SQL如下:

SELECT * FROM t_order WHERE order_id IN (1, 2);

那么路由的结果应为:

SELECT * FROM t_order_0 WHERE order_id IN (1, 2);
SELECT * FROM t_order_1 WHERE order_id IN (1, 2);

绑定表的关联查询与单表查询复杂度和性能相当。举例说明,如果一个包含绑定表的关联查询的SQL如下:

SELECT * FROM t_order o JOIN t_order_item i ON o.order_id=i.order_id  WHERE order_id IN (1, 2);

那么路由的结果应为:

SELECT * FROM t_order_0 o JOIN t_order_item_0 i ON o.order_id=i.order_id  WHERE order_id IN (1, 2);
SELECT * FROM t_order_1 o JOIN t_order_item_1 i ON o.order_id=i.order_id  WHERE order_id IN (1, 2);

标准路由源码:

@RequiredArgsConstructor
public final class StandardRoutingEngine implements RoutingEngine {
    //分片策略接口,具体实现有外部指定
    private final ShardingRule shardingRule;
    //逻辑表
    private final String logicTableName;
    //分片条件
    private final ShardingConditions shardingConditions;
   
    @Override
    public RoutingResult route() {
        return generateRoutingResult(get
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值