美文网首页我爱编程
sharding-sphere学习(1)之-[raw-examp

sharding-sphere学习(1)之-[raw-examp

作者: 码农进化史 | 来源:发表于2018-05-27 19:42 被阅读0次

发现梦想与现实的差距后,坚持就越来越远

前段时间在刷博客的时候,无意间刷到了一篇介绍数据库分库分表的框架,于是网上搜了一下,shardingjdbc 当当团队网团队开源的一个专做对于java开发在原生的jdbc层上封装的一层轻量级中间件。我们看一下它的官网(http://shardingjdbc.io/index_zh.html)给的介绍:

sharding-sphere

对于shardingjdbc来说无非就是通过java代码在原生的jdbc上封装了一层,如果说自己去研发一个这样的中间件也不是不可能。就是后期考虑到出现的bug、效率、性能等问题,没有一个更好的前期规划也很难完成。定位上面这个轻量级的框架通过上面给的架构图来说,无非就是在jdbc层进行更好的封装集成,从而形成一个加强版的JDBC连接数据库的工具。没有任何侵入性,完全可以兼容任何的ORM框架,这一点确实是可以值得一用的。


sharding-jdbc

下面我们来看看sharding-jdbc为我们提供的功能有哪些?官网也有具体的介绍:

  • 数据分片
    数据分片主要以分库+分表的操作、支持的sql语句查询方式以及分布式主键的处理方案等
  • 读写分离
    读写分离主要以一主多从、统一线程数据的一致性以及分库分表时的读写分离操作等
  • 事物处理
    主要针对TCC分布式事物处理解决
  • 分布式治理
    主要一些熔断措施,以及配置中心的配置。

基本的说明就这些,后续将会沿着例子区找到源码进行进一步的研究和探讨。接下来可以去github上将shardingjdbc-example(https://github.com/sharding-sphere/sharding-sphere-example)例子下载下来运行,如下图,由于版本原因选择branches版本下载:

分支
本机运行例子需要选择master版本的,dev是开发版本,暂时maven代码库还没有更新上去。
master
可以直接下载zip也可以直接使用:
git clone https://github.com/sharding-sphere/sharding-sphere-example.git

直接下载下来。然后将下载下来的项目导入到IDEA中如下图:

example运行例子

注意:当前我使用的sharding-jdbc版本是2.0.3。git可能会是最新版本。应该都可以用的运行的,只是目录有点不一样了。

我们来看看官网给的例子,首先在每个项目模块下面对java实现的每个ORM框架进行了组个demo演示,无论我们使用哪种框架,只需要导入所需的jar包便可以完美的和ORM框架结合。
首先我们先来看看在与原生的jdbc结合的时候sharding-jdbc是怎么实现分库分表的策略的。找到

sharding-jdbc-raw-jdbc-example
sharding-jdbc-raw-jdbc-example

该模块下的

sharding-jdbc-raw-jdbc-java-example // 原生代码与sharding-jdbc结合
/**仅读写分离操作*/
RawJdbcJavaMasterSlaveOnlyMain
/**读写分离+分库分表操作*/
RawJdbcJavaShardingAndMasterSlaveMain
/**分库分表操作*/
RawJdbcJavaShardingDatabaseAndTableMain
/**仅分库操作*/
RawJdbcJavaShardingDatabaseOnlyMain
/**仅做分表操作*/
RawJdbcJavaShardingTableOnlyMain

注意:在运行demo前请先将基本的数据库先初始化好,在每个模块的根目录下会有一个sql文件,是根据自己的业务来制定的建库规则来创建对应的库:


需要执行的建库sql

在创建好数据库后将会有12个对应的数据库,待后续example会使用到:


初始化example的数据库

下面将从分库模块学习使用入口:

/**仅分库操作*/
RawJdbcJavaShardingDatabaseOnlyMain

使用到的库:

  • demo_ds_0
  • demo_ds_1
    运行该example结果如下:
1.动态创建表成功--------------
2.插入数据成功--------------
3.打印 Equals 查询结果--------------
order_item_id:1, order_id:207575701002387456, user_id:10
order_item_id:2, order_id:207575701472149504, user_id:10
order_item_id:3, order_id:207575701568618496, user_id:10
order_item_id:4, order_id:207575701669281792, user_id:10
order_item_id:5, order_id:207575701803499520, user_id:10
order_item_id:6, order_id:207575701950300160, user_id:10
order_item_id:7, order_id:207575702038380544, user_id:10
order_item_id:8, order_id:207575702118072320, user_id:10
order_item_id:9, order_id:207575702256484352, user_id:10
4.打印使用 In 查询结果--------------
order_item_id:1, order_id:207575701405040640, user_id:11
order_item_id:2, order_id:207575701518286848, user_id:11
order_item_id:3, order_id:207575701623144448, user_id:11
order_item_id:4, order_id:207575701723807744, user_id:11
order_item_id:5, order_id:207575701899968512, user_id:11
order_item_id:6, order_id:207575701988048896, user_id:11
order_item_id:7, order_id:207575702080323584, user_id:11
order_item_id:8, order_id:207575702218735616, user_id:11
order_item_id:9, order_id:207575702290038784, user_id:11
order_item_id:1, order_id:207575701002387456, user_id:10
order_item_id:2, order_id:207575701472149504, user_id:10
order_item_id:3, order_id:207575701568618496, user_id:10
order_item_id:4, order_id:207575701669281792, user_id:10
order_item_id:5, order_id:207575701803499520, user_id:10
order_item_id:6, order_id:207575701950300160, user_id:10
order_item_id:7, order_id:207575702038380544, user_id:10
order_item_id:8, order_id:207575702118072320, user_id:10
order_item_id:9, order_id:207575702256484352, user_id:10
4.打印使用 Hint 查询结果--------------
order_item_id:1, order_id:207575701405040640, user_id:11
order_item_id:2, order_id:207575701518286848, user_id:11
order_item_id:3, order_id:207575701623144448, user_id:11
order_item_id:4, order_id:207575701723807744, user_id:11
order_item_id:5, order_id:207575701899968512, user_id:11
order_item_id:6, order_id:207575701988048896, user_id:11
order_item_id:7, order_id:207575702080323584, user_id:11
order_item_id:8, order_id:207575702218735616, user_id:11
order_item_id:9, order_id:207575702290038784, user_id:11

数据库中的表如图所示:


分库插入数据

基本执行步骤如下:

    /**
     * @author: ErnestFei
     * @date: 2018/5/27 19:15
     * @Description: 配置数据源
     */
    private static DataSource getShardingDataSource() throws SQLException {
        /**初始化sharding配置*/
        ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
        /**添加创建主订单表*/
        shardingRuleConfig.getTableRuleConfigs().add(getOrderTableRuleConfiguration());
        /**添加创建订单项表*/
        shardingRuleConfig.getTableRuleConfigs().add(getOrderItemTableRuleConfiguration());
        /**根据主订单表中的user_id字段定位该笔订单入库规则,这里使用user_id的奇偶数来定位插库入口*/
        shardingRuleConfig.setDefaultDatabaseShardingStrategyConfig(new InlineShardingStrategyConfiguration("user_id", "demo_ds_${user_id % 2}"));
        /**创建好数据源并加入配置中得到数据源配置*/
        return ShardingDataSourceFactory.createDataSource(createDataSourceMap(), shardingRuleConfig, new HashMap<String, Object>(), new Properties());
    }

    /**
     * @author: ErnestFei
     * @date: 2018/5/27 19:20
     * @Description: 主订单表规则的基本配置
     */
    private static TableRuleConfiguration getOrderTableRuleConfiguration() {
        TableRuleConfiguration orderTableRuleConfig = new TableRuleConfiguration();
        orderTableRuleConfig.setLogicTable("t_order");
        /**设置主键*/
        orderTableRuleConfig.setKeyGeneratorColumnName("order_id");
        return orderTableRuleConfig;
    }
    
    /**
     * @author: ErnestFei
     * @date: 2018/5/27 19:22 
     * @Description: 订单项目表的配置规则
     */
    private static TableRuleConfiguration getOrderItemTableRuleConfiguration() {
        TableRuleConfiguration orderItemTableRuleConfig = new TableRuleConfiguration();
        orderItemTableRuleConfig.setLogicTable("t_order_item");
        return orderItemTableRuleConfig;
    }
    
    /**
     * @author: ErnestFei
     * @date: 2018/5/27 19:22 
     * @Description: 创建两个动态数据源 demo_ds_0 、 demo_ds_1
     */
    private static Map<String, DataSource> createDataSourceMap() {
        Map<String, DataSource> result = new HashMap<>(2, 1);
        result.put("demo_ds_0", DataSourceUtil.createDataSource("demo_ds_0"));
        result.put("demo_ds_1", DataSourceUtil.createDataSource("demo_ds_1"));
        return result;
    }

执行的具体操作类关键实现如下:

    private final DataSource dataSource;
    
    /**初始化数据源*/
    public RawJdbcRepository(final DataSource dataSource) {
        this.dataSource = dataSource;
    }
    
    public void demo() throws SQLException {
        /**创建表*/
        System.out.println("1.动态创建表--------------");
        this.createTable();
        /**插入数据*/
        System.out.println("2.插入数据--------------");
        this.insertData();
        /**打印查询*/
        System.out.println("3.打印 Equals 查询结果--------------");
        printEqualsSelect();
        System.out.println("4.打印使用 In 查询结果--------------");
        printInSelect();
        System.out.println("4.打印使用 Hint 查询结果--------------");
        printHintSimpleSelect();
//        dropTable();
    }
    
    /**
     * @author: ErnestFei
     * @date: 2018/5/27 19:24 
     * @Description: 动态创建表
     */
    public void createTable() throws SQLException {
        execute(dataSource, "CREATE TABLE IF NOT EXISTS t_order (order_id BIGINT NOT NULL AUTO_INCREMENT, user_id INT NOT NULL, status VARCHAR(50), PRIMARY KEY (order_id))");
        execute(dataSource, "CREATE TABLE IF NOT EXISTS t_order_item (order_item_id BIGINT NOT NULL AUTO_INCREMENT, order_id BIGINT NOT NULL, user_id INT NOT NULL, PRIMARY KEY (order_item_id))");
    }
    
    /**
     * @author: ErnestFei
     * @date: 2018/5/27 19:25 
     * @Description: 删除表
     */
    public void dropTable() throws SQLException {
        execute(dataSource, "DROP TABLE t_order_item");
        execute(dataSource, "DROP TABLE t_order");
    }
    
    /**
     * @author: ErnestFei
     * @date: 2018/5/27 19:25 
     * @Description: 插入数据
     */
    public void insertData() throws SQLException {
        for (int i = 1; i < 10; i++) {
            long orderId = this.executeAndGetGeneratedKey(dataSource, "INSERT INTO t_order (user_id, status) VALUES (10, 'INIT')");
            this.execute(dataSource, String.format("INSERT INTO t_order_item (order_id, user_id) VALUES (%d, 10)", orderId));
            orderId = this.executeAndGetGeneratedKey(dataSource, "INSERT INTO t_order (user_id, status) VALUES (11, 'INIT')");
            this.execute(dataSource, String.format("INSERT INTO t_order_item (order_id, user_id) VALUES (%d, 11)", orderId));
        }
    }
    
    /**
     * @author: ErnestFei
     * @date: 2018/5/27 19:25 
     * @Description: 使用 Equals 查询数据
     */
    public void printEqualsSelect() throws SQLException {
        String sql = "SELECT i.* FROM t_order o JOIN t_order_item i ON o.order_id=i.order_id WHERE o.user_id=?";
        try (
                Connection conn = dataSource.getConnection();
                PreparedStatement preparedStatement = conn.prepareStatement(sql)) {
            preparedStatement.setInt(1, 10);
            printSimpleSelect(preparedStatement);
        }
    }
    
    /**
     * @author: ErnestFei
     * @date: 2018/5/27 19:26 
     * @Description: 使用 In 查询数据
     */
    public void printInSelect() throws SQLException {
        String sql = "SELECT i.* FROM t_order o JOIN t_order_item i ON o.order_id=i.order_id WHERE o.user_id IN (?, ?)";
        try (
                Connection conn = dataSource.getConnection();
                PreparedStatement preparedStatement = conn.prepareStatement(sql)) {
            preparedStatement.setInt(1, 10);
            preparedStatement.setInt(2, 11);
            printSimpleSelect(preparedStatement);
        }
    }

    /**
     * @author: ErnestFei
     * @date: 2018/5/27 19:27 
     * @Description: 使用 Hint 查询数据
     */
    public void printHintSimpleSelect() throws SQLException {
        String sql = "SELECT i.* FROM t_order o JOIN t_order_item i ON o.order_id=i.order_id";
        try (
                HintManager hintManager = HintManager.getInstance();
                Connection conn = dataSource.getConnection();
                PreparedStatement preparedStatement = conn.prepareStatement(sql)) {
            hintManager.addDatabaseShardingValue("t_order", "user_id", 11);
            printSimpleSelect(preparedStatement);
        }
    }
    
    /**
     * @author: ErnestFei
     * @date: 2018/5/27 19:27 
     * @Description: 打印并遍历查询结果
     */
    private void printSimpleSelect(final PreparedStatement preparedStatement) throws SQLException {
        try (ResultSet rs = preparedStatement.executeQuery()) {
            while (rs.next()) {
                System.out.print("order_item_id:" + rs.getLong(1) + ", ");
                System.out.print("order_id:" + rs.getLong(2) + ", ");
                System.out.print("user_id:" + rs.getInt(3));
                System.out.println();
            }
        }
    }
    
    /**
     * @author: ErnestFei
     * @date: 2018/5/27 19:27 
     * @Description: 执行连接数据源
     */
    private void execute(final DataSource dataSource, final String sql) throws SQLException {
        try (
                Connection conn = dataSource.getConnection();
                Statement statement = conn.createStatement()) {
            statement.execute(sql);
        }
    }
    
    /**
     * @author: ErnestFei
     * @date: 2018/5/27 19:28 
     * @Description: 插入数据并返回主键参数值
     */
    private long executeAndGetGeneratedKey(final DataSource dataSource, final String sql) throws SQLException {
        long result = -1;
        try (
                Connection conn = dataSource.getConnection();
                Statement statement = conn.createStatement()) {
            statement.executeUpdate(sql, Statement.RETURN_GENERATED_KEYS);
            ResultSet resultSet = statement.getGeneratedKeys();
            if (resultSet.next()) {
                result = resultSet.getLong(1);
            }
        }
        return result;
    }

至此可看出在分库策略上sharding-jdbc做的流程,可将通过user_id定位到制定规则的数据库中,并在插入数据时进行动态分配数据源的数据,从而将数据均分落地到到两个库所对应的克隆的实际表中,实现分库操作。该example是通过直接取模分配数据源,当然我们也可以通过自己定的分片规则算法进行实现分片操作。具体的实现流程说明下篇继续tfyy。。。

相关文章

网友评论

    本文标题:sharding-sphere学习(1)之-[raw-examp

    本文链接:https://www.haomeiwen.com/subject/jdxijftx.html