文档章节

sharding-jdbc分库分表规则(1)-单表查询

xiaomin0322
 xiaomin0322
发布于 06/07 14:47
字数 1571
阅读 30
收藏 3
点赞 0
评论 0

前言

当数据量到达一定数量级的时候,一般都会考虑分库分表。sharding-jdbc是一个开源的客户端分库分表基础类库,以一个jar包的形式提供,基于原生的JDBC驱动进行增强,基本能够无缝整合旧代码,非常的便捷。本小节以一个最简单的单表查询浅析概要流程。

建库建表

ds_jdbc_0 t_order_0 , t_order_1
ds_jdbc_1 t_order_0 , t_order_1



订单表逻辑语名: 
CREATE TABLE IF NOT EXISTS t_order (order_id INT NOT NULL, user_id INT NOT NULL, status VARCHAR(50), PRIMARY KEY (order_id))

配置

为简单起见,使用基本的jdbc进行操作,最精简的代码如下:

public final class SingleSelect {

    public static void main(final String[] args) throws SQLException {
        DataSource dataSource = getOrderShardingDataSource();
        printSingleSelect(dataSource);
    }

    private static ShardingDataSource getOrderShardingDataSource() {
        DataSourceRule dataSourceRule = new DataSourceRule(createDataSourceMap());
        TableRule orderTableRule = TableRule.builder("t_order").actualTables(Arrays.asList("t_order_0", "t_order_1")).dataSourceRule(dataSourceRule).build();
        ShardingRule shardingRule = ShardingRule.builder().dataSourceRule(dataSourceRule).tableRules(Arrays.asList(orderTableRule))
                .databaseShardingStrategy(new DatabaseShardingStrategy("user_id", new ModuloDatabaseShardingAlgorithm()))
                .tableShardingStrategy(new TableShardingStrategy("order_id", new ModuloTableShardingAlgorithm())).build();
        return new ShardingDataSource(shardingRule);
    }

    private static void printSingleSelect(final DataSource dataSource) throws SQLException {
        String sql = "SELECT * FROM t_order where user_id=? and order_id=?";
        try (
            Connection conn = dataSource.getConnection();
            PreparedStatement preparedStatement = conn.prepareStatement(sql)) {
            preparedStatement.setInt(1, 10);
            preparedStatement.setInt(2, 1001);
            try (ResultSet rs = preparedStatement.executeQuery()) {
                while (rs.next()) {
                    System.out.println(rs.getInt(1));
                    System.out.println(rs.getInt(2));
                    System.out.println(rs.getInt(3));
                }
            }
        }
    }
    private static DataSource createDataSource(final String dataSourceName) {
        BasicDataSource result = new BasicDataSource();
        result.setDriverClassName(com.mysql.jdbc.Driver.class.getName());
        result.setUrl(String.format("jdbc:mysql://127.0.0.1:3306/%s", dataSourceName));
        result.setUsername("root");
        result.setPassword("123456");
        return result;
    }
    private static Map<String, DataSource> createDataSourceMap() {
        Map<String, DataSource> result = new HashMap<>(2);
        result.put("ds_jdbc_0", createDataSource("ds_jdbc_0"));
        result.put("ds_jdbc_1", createDataSource("ds_jdbc_1"));
        return result;
    }
}

分库分表最主要有几个配置: 
1. 有多少个数据源 
2. 每张表的逻辑表名和所有物理表名 
3. 用什么列进行分库以及分库算法 
4. 用什么列进行分表以及分表算法

本示例定义了两个数据源: ds_jdbc_0 和 ds_jdbc_1,定义了逻辑表:t_order,以及物理表:t_order_0 和 t_order_0。采用 user_id列进行分库,order_id列进行分表。一切准备就绪,我们的目标是执行如下的语句:

SELECT * FROM t_order where user_id=10 and order_id=1001
  • 1

我们想实现如下的目标: 
分库: 
user_id % 2 = 0 的数据存储到 ds_jdbc_0 ,为1的数据存储到 ds_jdbc_1 
分表: 
order_id % 2 = 0 的数据存储到 t_order_0 ,为1的数据存储到 t_order_1

这属于业务的范畴,我们必须清楚告知sharding-jdbc我们的意图,所以要提供分库分表策略类, 
看看分库策略类:

public final class ModuloDatabaseShardingAlgorithm implements SingleKeyDatabaseShardingAlgorithm<Integer> {

    @Override
    public String doEqualSharding(final Collection<String> dataSourceNames, final ShardingValue<Integer> shardingValue) {
        for (String each : dataSourceNames) {
            if (each.endsWith(shardingValue.getValue() % 2 + "")) {
                return each;
            }
        }
        throw new IllegalArgumentException();
    }

    @Override
    public Collection<String> doInSharding(final Collection<String> dataSourceNames, final ShardingValue<Integer> shardingValue) {
        return null;
    }

    @Override
    public Collection<String> doBetweenSharding(final Collection<String> dataSourceNames, final ShardingValue<Integer> shardingValue) {
        return null;
    }
}

由于我们使用了 = 号条件进行查询,所以只实现了 doEqualSharding 这个方法。代码非常简单,参数dataSourceNames的值为[ds_jdbc_0 , ds_jdbc_1],而shardingValue在执行的时候可以获取到 user_id=10这个值,在doEqualSharding 中,我们自己根据user_id的值返回路由的库的名称。

接下来看看分表策略类:

public final class ModuloTableShardingAlgorithm implements SingleKeyTableShardingAlgorithm<Integer> {

    @Override
    public String doEqualSharding(final Collection<String> tableNames, final ShardingValue<Integer> shardingValue) {
        for (String each : tableNames) {
            if (each.endsWith(shardingValue.getValue() % 2 + "")) {
                return each;
            }
        }
        throw new UnsupportedOperationException();
    }

    @Override
    public Collection<String> doInSharding(final Collection<String> tableNames, final ShardingValue<Integer> shardingValue) {
        return null;
    }

    @Override
    public Collection<String> doBetweenSharding(final Collection<String> tableNames, final ShardingValue<Integer> shardingValue) {
        return null;
    }
}

一样实现了 doEqualSharding这个方法,因为我们的条件中有 order_id=1001,在执行回调时,tableNames的值为[t_order_0 ,t_order_1 ],我们可以决定如何路由到真实的表名。

流程浅析

先来看个基本的流程图:

这里写图片描述

我们再来看看我们的目标sql语句:

SELECT * FROM t_order where user_id=10 and order_id=1001
  • 1
  1. 通过sql解析发现有一张逻辑表名称:t_order

    发现两个条件: t_order.userId = 10 和 t_order.order_id = 1001

  2. 通过 t_order 找到对应的表配置规则 TableRule,这里定义了两个物理表: t_order_0和t_order_1

  3. 根据 TableRule找出目标数据源集合

    通过TableRule找到DatabaseShardingStrategy,得到分库列:user_id 
    通过t_order 和 user_id联合为key从条件中查找,找到了t_order.userId = 10, 
    再结合参数值(10),得到分片值 
    ShardingValue(logicTableName=t_order, columnName=user_id, value=10), 
    调用自定义分库策略类(传输[ds_jdbc_0 , ds_jdbc_1],ShardingValue),得到最终的数据源名称集合[ds_jdbc_0]

  4. 根据TableRule和数据源 [ds_jdbc_0] 找到物理表

    通过TableShardingStrategy找到表的分片列: order_id 
    通过t_order 和 order_id联合为key从条件中查找,找到了order_id=1001,再结合参数值(1001),得到分片值 
    ShardingValue(logicTableName=t_order, columnName=order_id, value=1001), 
    调用自定义分表策略类(传输[t_order_0,t_order_1],ShardingValue),得到[ds_jdbc_0]下的最终物理表集合[t_order_1]

  5. 根据数据源和物理表,得到 DataNode的集合

    根据得到的[ds_jdbc_0] 和 [t_order_1],构建 DataNode集合,每一个DataNode表示 xx库.xx表,此示例下得到一个DataNode实体: [ds_jdbc_0].[t_order_1]

  6. 根据 DataNode生成TableUnits集合

    TableUnit由 逻辑表,物理库,物理表 三个字段组成, 
    此示例为: t_order 、ds_jdbc_0 、t_order_1

  7. SQL重写

    构建重写引擎SQLRewriteEngine,根据TableUnits生成对应最终的sql语句执行单元(替换成最终表名),得到执行单元集合(ExecutionUnits),一个执行单元表示在哪个库,执行什么sql语句

  8. ExecutionUnits转换为PreparedStatement,最后又转为PreparedStatementUnit

  9. 线程池并发执行PreparedStatementUnit,最后再合并结果返回

多库单表又如何

通过上面的分析,我们已经知道了单库单表的基本查询逻辑,现在把sql简单调整为:

SELECT * FROM t_order where order_id=1001
  • 1

这次,我们发现搜索条件并没有分库键,这时候,引擎并不会调用分库策略类,直接认定目标库为[ds_jdbc_0,ds_jdbc_1],而分表的逻辑是不变的,既然目标库有两个,后面生成的DataNode,TableUnits,PreparedStatementUnit 将是以前数量的两倍,所以这回,引擎最终将会发起多个sql语句的并发执行,并合并最终的结果再返回。

总结

以上基于一个最简单的查询拆解了基本的流程,当然,sql解析的细节还是很复杂的,但不是本文关注的重点,本文主要关注一个简单的sql语句,在sharding-jdbc下是如何达到分库分表的目的的,后续再分析更多的sql语句的执行。

参考

http://shardingjdbc.io/index_zh.html

本文转载自:https://blog.csdn.net/yanyan19880509/article/details/78008461

共有 人打赏支持
xiaomin0322
粉丝 81
博文 3437
码字总数 123902
作品 0
上海
架构师
【死磕Sharding-jdbc】—–基于ssm

原文作者:阿飞Javaer 原文链接:https://www.jianshu.com/p/602e24845ed3 本篇文章讲解如何在ssm(spring、springmvc、mybatis)结构的程序上集成sharding-jdbc(版本为1.5.4.1)进行分库分...

飞哥-Javaer
05/05
0
0
【死磕Sharding-jdbc】—基于 SSM 集成sharding-jdbc2.0.3

原文作者:阿飞Javaer 原文链接:https://www.jianshu.com/p/7b6997c3586d 本篇文章讲解如何在ssm(spring、springmvc、mybatis)结构的程序上集成sharding-jdbc(版本为2.0.3)进行分库分表...

飞哥-Javaer
05/27
0
0
MySQL多数据源笔记5-ShardingJDBC实战

Sharding-JDBC集分库分表、读写分离、分布式主键、柔性事务和数据治理与一身,提供一站式的解决分布式关系型数据库的解决方案。 从2.x版本开始,Sharding-JDBC正式将包名、Maven坐标、码云仓...

狂小白
03/19
0
0
崛起于Springboot之Mysql分库分表-Sharding-Jdbc(7)

序言:当当开发的一个中间件,sharding-jdbc sharding-jdbc官网API,听说能用它也能读写分离,目前没有搭建出springboot+sharding-jdbc的mysql读写分离,先暂时告一段落,这一篇博客主要讲述...

木九天
06/26
0
0
【死磕Sharding-jdbc】—–路由&执行

原文作者:阿飞Javaer 原文链接:https://www.jianshu.com/p/09efada2d086 继续以模块中的为基础,剖析分库分表简单查询SQL实现--,即如何执行简单的查询SQL,接下来的分析以执行SQL语句为例...

飞哥-Javaer
05/03
0
0
关于分库分表,这有一套大而全的轻量级架构设计思路

作者介绍 这里介绍设计分库分表框架时应该考虑的设计要点,并给出相应的解决方案,为后面实现分库分表框架dbsplit提供理论支撑。 简单来说,数据的切分就是通过某种特定的条件,将我们存放在...

DBAplus社群
04/16
0
0
sharding-jdbc事务解读

序言 sharding-jdbc在分库分表方面提供了很大的便利性,在使用DB的时候,通常都会涉及到事务这个概念,而在分库分表的环境上再加上事务,就会使事情变得复杂起来。本章试图剖析sharding-jdbc...

xiaomin0322
06/06
0
0
sharding-jdbc源码分析—准备工作

原文作者:阿飞Javaer 原文链接:https://www.jianshu.com/p/7831817c1da8 接下来对sharding-jdbc源码的分析基于tag为源码,根据sharding-jdbc Features深入学习sharding-jdbc的几个主要特性...

飞哥-Javaer
05/03
0
0
数据库中间件 Sharding-JDBC 源码分析 —— JDBC实现与读写分离

摘要: 原创出处 http://www.iocoder.cn/Sharding-JDBC/jdbc-implement-and-read-write-splitting/ 「芋道源码」欢迎转载,保留摘要,谢谢! 本文主要基于 Sharding-JDBC 1.5.0 正式版 1. 概述...

芋道源码
2017/10/22
0
0
在实践中使用ShardingJdbc组件的正确姿势(一)

文章摘要:在设计系统时,需要根据实际的业务情况来选用合适的组件构建系统。 在互联网时代,随着业务数量的暴增和应用规模的不断扩大,无论是oracle还是mysql这样子的关系型数据库,都会面临...

癫狂侠
05/08
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

设计模式:单例模式

单例模式的定义是确保某个类在任何情况下都只有一个实例,并且需要提供一个全局的访问点供调用者访问该实例的一种模式。 实现以上模式基于以下必须遵守的两点: 1.构造方法私有化 2.提供一个...

人觉非常君
14分钟前
0
0
《Linux Perf Master》Edition 0.4 发布

在线阅读:https://riboseyim.gitbook.io/perf 在线阅读:https://www.gitbook.com/book/riboseyim/linux-perf-master/details 百度网盘【pdf、mobi、ePub】:https://pan.baidu.com/s/1C20T......

RiboseYim
25分钟前
0
0
conda 换源

https://mirrors.tuna.tsinghua.edu.cn/help/anaconda/ conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/conda config --add channels https://mir......

阿豪boy
35分钟前
0
0
Confluence 6 安装补丁类文件

Atlassian 支持或者 Atlassian 缺陷修复小组可能针对有一些关键问题会提供补丁来解决这些问题,但是这些问题还没有放到下一个更新版本中。这些问题将会使用 Class 类文件同时在官方 Jira bug...

honeymose
44分钟前
0
0
非常实用的IDEA插件之总结

1、Alibaba Java Coding Guidelines 经过247天的持续研发,阿里巴巴于10月14日在杭州云栖大会上,正式发布众所期待的《阿里巴巴Java开发规约》扫描插件!该插件由阿里巴巴P3C项目组研发。P3C...

Gibbons
53分钟前
0
0
Tomcat介绍,安装jdk,安装tomcat,配置Tomcat监听80端口

Tomcat介绍 Tomcat是Apache软件基金会(Apache Software Foundation)的Jakarta项目中的一个核心项目,由Apache、Sun和其他一些公司及个人共同开发而成。 java程序写的网站用tomcat+jdk来运行...

TaoXu
53分钟前
0
0
TensorFlow,从一个 Android Demo 开始

TensorFlow Android Demo 项目地址 Machine Learning 既然提到了 TensorFlow,那是不是得神经网络、机器学习了解下? 如果你能坚持把 机器学习速成课程 给啃完了,觉得还挺有兴趣的,那可以考...

孟飞阳
55分钟前
0
0
JVM学习笔记二:内存结构规范

1、JVM基本结构图 2、java堆(Heap) 3、方法区(Method Area) 4、程序计数器 5、JAVA栈图解 局部变量表:八大基本类型,还可以存储引用类型 上一篇:JVM学习笔记一:类加载机制介绍...

刘祖鹏
今天
0
0
mui集成微信H5支付(返回白屏问题已经解决)

一.项目需求 因为公司人员缺少,没有专门开发安卓和ios的人员,为了项目尽早上线采用了混合APP开发的方式,我选择了MUI混合开发框架,项目中需要在用户购买VIP会员的时候进行支付,所以需要在项目...

银装素裹
今天
1
0
SpringBoot集成Redis--配置自定义的RedisCacheManager

配置自定义的RedisCacheManager--1自定义键生成规则 默认的键生成器 当不指定缓存的key时,SpringBoot会使用SimpleKeyGenerator生成key。 SimpleKeyGenerator SimpleKey 查看源码可以发现,它...

karma123
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部